본문으로 건너뛰기

프로토콜 문법

프로토콜을 정의하는 방법과 프로토콜에 요구 사항을 추가하는 방법을 살펴본다.

프로토콜 정의

프로토콜을 정의하는 문법은 클래스나 구조체 또는 열거형을 정의할 때 사용하는 문법과 매우 유사하다.

protocol MyProtocol {
// implementing requirement
}

프로토콜을 정의하기 위해서는 protocol 키워드를 사용하며, 그 다음으로 프로토콜 이름이 위치한다. 그런 다음 중괄호 사이에 프로토콜이 정의한 요구 사항을 입력한다. 커스텀 타입은 타입 이름 뒤에 콜론으로 구분해 프로토콜의 이름을 위치시킴으로써 해당 타입이 따르는 특정 프로토콜을 나타낼 수 있다.

struct MyStruct: MyProtocol {
// implementing requirement
}

타입은 다중 프로토콜을 따를 수도 있다. 타입이 따르는 다중 프로토콜은 콜론으로 구분해 열거한다.

struct MyStruct: MyProtocol, AnotherProtocol, ThirdProtocol {
// implementing requirement
}

타입이 다중 프로토콜을 따르게 하는 것은 프로토콜 지향 프로그래밍에서 매우 중요한 개념이다. 이 개념은 프로토콜 컴포지션protocol composition으로 알려져 있다.

프로퍼티 요구 사항

프로토콜은 프로토콜을 따르는 타입에 명시된 이름과 타입을 갖는 특정 프로퍼티를 제공할 것을 요구할 수 있다. 프로토콜은 자세한 구현체는 프로토콜을 따르는 타입에 맞기기 때문에 프로퍼티가 저장 프로퍼티store property나 연산 프로퍼티computed property가 돼야 한다는 것을 말하지는 않는다.

프로토콜에서 프로퍼티를 정의할 때 getset 키워드를 사용해 프로퍼티가 읽기 전용 프로퍼티인지 읽기 쓰기 프로퍼티인지를 반드시 명시해줘야만 한다. 또한 프로토콜에서는 타입 추론type inference을 사용할 수 없으므로 프로퍼티의 타입 역시 명시해야만 한다.

protocol FullName {
var firstName: String {get set}
var lastName: String {get set}
}

위 예에서 firstNamelastName 이라는 이름을 갖는 두 개의 읽기 쓰기 프로퍼티를 정의했다. 이 프로토콜을 따르는 모든 타입은 두 프로퍼티를 반드시 구현해야 한다.

get 키워드만을 사용하면 읽기 전용 프로퍼티를 정의할 수 있다.

var readOnly: String {get}

static 키워드를 사용하면 정적 프로퍼티를 정의할 수 있다.

static var typeProperty: String {get}

메서드 요구 사항

프로토콜은 프로토콜을 따르는 타입에 구체적인 메서드를 제공할 것을 요구할 수 있다. 프로토콜에 메서드를 정의할 때에는 메서드 매개변수에 기본 값을 추가하는 것은 허용되지 않는다.

protocol FullName {
var firstName: String {get set}
var lastName: String {get set}

func getFullName() -> String
}

위 예의 FullName 프로토콜은 getFullName() 이라는 메서드와 firstNamelastName 이라는 두 개의 읽기 쓰기 프로퍼티를 요구한다.

구조체와 같은 값 타입의 경우 메서드가 메서드 자신이 속해 있는 인스턴스를 변경하고자 의도하는 경우 반드시 메서드 정의부 앞부분에 mutating 키워드를 추가해야만 한다.

mutating func changeName()

mutating 키워드는 오직 값(구조체 또는 열거형) 타입에만 사용된다.

선택 가능한 요구 사항

프로토콜이 선택 가능한 요구 사항optional requirements을 정의하기를 바라는 경우가 있다. 선택 가능한 요구 사항은 메서드나 프로퍼티의 구현을 요구하지 않는다. 선택 가능한 요구 사항을 사용하기 위해서는 프로토콜을 표시할 때 @objc 속성이 프로토콜 앞부분에 위치해야 한다.

정보

오직 클래스만 @objc 속성을 사용하는 프로토콜을 채택 수 있다. 구조체와 열거형은 이러한 프로토콜을 채택할 수 없다.


optional 키워드를 사용하면 프로퍼티나 메서드가 선택 가능하다는 것으로 표시할 수 있다.

@objc protocol Phone {
var phoneNumber: String {get set}
@objc optional var emailAddress: String {get set}
func dialNumber()
@objc optional func getEmail()
}