프로토콜을 한번에 정리하려니 너무 길어져서 좀 짤라서.......
먼저 타입의 요구사항부터
타입이 구현해야 하는 요구사항에 대한 정의
프로토콜은 특정 작업이나 기능에 적합한 메서드, 프로퍼티, 기타 요구사항에 대한 청사진을 정의합니다.
프로토콜은 클래스, 구조체, 열거형에 채택되어서 요구사항에 대한 실제 구현을 제공할 수 있습니다.
프로토콜의 요구 사항을 충족하는 모든 타입에 대해서 해당 프로토콜을 준수한다고 합니다.
준수하는 타입이 구현해야 하는 요구사항을 지정하는 것 외에 요구사항 중 일부를 구현하거나 준수한 타입이 활용할 수 있는 추가 기능을 구현하도록 프로토콜을 확장할 수 있습니다.
클래스, 구조체, 열거형과 유사한 반법으로 프로토콜을 정의할 수 있습니다.
콜론(:) 으로 구분해서 타입 이름 뒤에 프로토콜명을 작성해서 프로토콜을 채택 합니다.
여러개는 콤마로 구분합니다.
만약 수퍼클래스를 가진 클래스의 경우에는 프로토콜 채택 전에 수퍼클래스 명을 먼저 작성합니다.
Note 프로토콜은 타입이기 때문에 Swift의 다른 타입들 처럼 대문자로 시작해야 합니다.
Property Requirements
프로토콜은 준수하는 타입에게 제공하기 위해서 특정 이름이나 타입으로 된 인스턴스 프로퍼티나 타입 프로퍼티를 요구할 수 있습니다.
프로토콜은 프로퍼티가 저장 프로퍼티인지, 계산 프로퍼티인지는 지정하지 않고 프로퍼티 이름과 타입만 지정해주면 됩니다.
프로토콜은 각 프로퍼티가 gettable인지 gettable 및 settable인지 지정해야 합니다.
만약에 프로토콜 프로퍼티 요구사항이 gettable 이면서 settable이면 해당 프로퍼티는 상수 저장 프로퍼티나 읽기 전용 계산 프로퍼티로는 요구조건을 충족할 수 없습니다.
만약 프로토콜 프로퍼티의 요구사항이 gettable만 있다면 모든 종류의 프로퍼티로 요구사항 충족이 가능하며, 필요한 경우 settable 설정도 할 수 있습니다.
프로퍼티 요구사항은 항상 var 키워드와 함께 변수 프로퍼티로 선언됩니다.
gettable 및 settable 프로퍼티들은 타입 선언 뒤에 { get set } 으로 표시되고, gettable 프로퍼티들은 { get } 으로 표시됩니다.
프로토콜에서 타입 프로퍼티의 요구사항을 정의할때는 항상 앞에 static 키워드를 붙여야 합니다.
이 규칙은 타입 프로퍼티 요구사항이 클래스에 의해 구현될때 class 또는 static 키워드를 붙일 수 있는 경우에도 적용됩니다.
다음 예제는 하나의 인스턴스 프로퍼티 요구사항을 가지는 프로토콜 입니다.
FullyNamed 프로토콜은 준수하는 타입에 full Name을 요구합니다.
프로토콜은 준수하는 타입의 특성에 대해 어떤 것도 지정하지 않고, 타입이 fullName을 제공해야 한다고만 정의합니다.
이 프로토콜에 따르면 모든 FullyNamed 타입은 String 타입인 fullName 이라는 gettable 인스턴스 프로퍼티를 가져야 합니다.
아래는 FullyNamed를 채택하고 준수하는 간단한 구조체 에제 입니다.
예제에서 Person 이라는 구조체를 생성하고 FullyNamed를 채택합니다.
Person의 인스턴스는 fullName 이라는 String 타입의 단일 저장 프로퍼티를 가집니다.
이것은 FullyNamed 프로토콜의 단일 요구 사항과 일치하고, Person은 프로토콜은 올바르게 준수 하고 있다고 얘기합니다. (Swift에서 프로토콜 요구사항이 충족되지 않으면 컴파일 에러가 발생)
FullyNamed를 채택하고 준수하는 더 복잡한 코드 예제
gettable 요구사항만 있는 프로퍼티에 settable 설정이 가능하다고 했는데
프로토콜의 프로퍼티가 요구사항으로 gettable만 있을때 구현시 settable도 설정 가능합니다.
Note
준수? 채택?
프로토콜을 채택하고 준수하는 설명
준수하고 채택하기 위해 SomeClass와 SomeProtocol을 생성
SomeProtocol은 Sring 저장 인스턴스 프로퍼티 1개, 인스턴스 메서드 1개를 요구사항으로 가집니다.
채택? 채택은 말그대로 채택!?
프로토콜을 사용하기 위해 채택하기는 했지만 요구사항을 준수하지는 않은 상태
위 코드는 SomeProtocol을 채택하긴 했지만 준수하지는 않았습니다.
여기서 프로토콜을 준수하게 되면
Method Requirements
프로토콜은 준수하는 타입에서 지정하는 인스턴스 매서드나 타입 메서드 구현을 요구할 수 있습니다.
일반적인 인스턴스 메서드나 타입 메서드 처럼 같은 방식으로 프로토콜 정의의 일부분으로 작성되지만, 중괄호나 메서드 본문은 작성하지 않습니다.
일반적인 메서드와 같은 규칙에 따라 가변 파라미터(Variadic parameters)도 허용됩니다.
But! 프로토콜 정의 내에서 메서드 파라미터의 기본값을 지정할 수 없습니다.
타입 프로퍼티의 요구사항과 같이 프로토콜에서 타입 메서드 요구사항 앞에 static 키워드를 작성해야 합니다.
클래스에 구현될때 타입 메서드 요구사항에 class 나 static 키워드가 붙는 경우도 마찬가지입니다.
예제를 통해 단일 인스턴스 메서드 요구사항을 가지는 프토콜을 살펴보면
RandomNumberGenerator 프로토콜은 Double 값을 반환하는 randon() 이라는 메서드를 준수하도록 요구합니다.
RandomNumberGenerator 는 난수가 생성되는 방법에 대해 어떠한 가정도 하지 않습니다.
다음 예제에서 RandomNumberGenerator 프로토콜을 채택하고 실제 난수가 생성되는 방법을 구현하여 프로토콜을 준수한 코드입니다.
Mutating Method Requirements
간혹 메서드가 속한 인스턴스를 수정하거나 변경해야 할 필요가 있습니다.
값 타입(구조체와 열거형)에 대한 인스턴스 메서드는 func 키워드 앞에 mutating 키워드를 둬서 메서드가 인스턴스와 해당 인스턴스에 속한 모든 프로퍼티를 수정 가능하게 합니다.
프로토콜을 채택하는 모든 타입의 인스턴스를 변경하기 위한 프로토콜 인스턴스 메서드 요구사항을 정의하는 경우 프로토콜 정의의 부분으로 mutating 키워드를 표시합니다. 이렇게 하면 구조체와 열거형이 프로토콜을 채택하고 메서드 요구사항을 충족할 수 있습니다.
예제를 통해 살펴봅시다.
class mutating도 해보기 위해서 그냥 공식 문서 예제말고
SomeProtocol이라는 프로토콜을 하나 만들어 줍니다. 이 프로토콜은 someMethod(_:) 요구조건이 있는데 메서드의 파라미터로 입력받은 값으로 인스턴스의 이름 프로퍼티를 수정할거에요.
그래서 mutating 키워드로 표시합니다.
그리고 SomeStructure 구조체를 만들어서 프로토콜을 채택하고 준수 합니다.
mutating 키워드를 사용하지 않으면 에러가 발생합니다.
반대로 클래스는 mutating 키워드를 안써도 되고 쓰면 에러가 나요
왜 그럴까 생각해보면 클래스는 참조타입이기 때문에 인스턴스의 프로퍼티 값을 수정이 가능합니다.
비슷한예로 class는 상수(let) 으로 선언해도 프로퍼티 수정이 가능합니다.
Note
mutating 으로 프로토콜 인스턴스 메서드 요구사항을 표시하면 클래스에 대한 메서드의 구현을 작성할때 mutating 키워드를 작성할 필요가 없습니다. mutating 키워드는 구조체와 열거형에 의해서만 사용됩니다.
Initializer Requirements
프로토콜은 준수하는 타입에 초기화 구문 구현을 요구할 수 있습니다.
일반적인 초기화 구문과 같은 방식으로 정의하지만 중괄호 내 본문은 없습니다.
Class Implementations of Protocol Initializer Requirements
프로토콜 초기화 구문을 통해 지정 초기화 구문이나 편의 초기화 구문을 준수하는 클래스에 구현을 요구할 수 있습니다. 두 방법 모두 초기화 구문에 required를 표시해야 합니다.
required 수식어를 사용하면 준수하는 클래스를 상속받는 서브클래스들에게 초기화 구문을 필수로 요구할 수 있습니다.
Note
final 클래스는 하위 클래스가 될 수 없으므로 final 수식어로 표시된 클래스에 required 수식어를 프로토콜 초기화 구문 구현에 표시할 필요가 없습니다.
서브 클래스가 수퍼 클래스의 지정 초기화 구문을 재정의 하고 프로토콜로부터 같은 요구사항을 구현하게 되면 required 와 override가 모두 표시됩니다.
Failable Initializer Requirements
프로토콜은 준수하는 타입에 요구사항으로 실패 가능한 초기화 구문(Failable Initializers) 요구할 수 있습니다.
실패 가능한 초기화 구문 요구사항을 준수하는 타입에 실패가능하거나 실패 불가능한 초기화 구문에 의해 만족될 수 있습니다. 실패 불가능한 초기화 구문 요구사항은 실패 불가능한 초기화 구분이나 암묵적으로 언래핑된 초기화 가능 구문에 의해 만족될 수 있습니다.
'Swift > 꼬꼬무' 카테고리의 다른 글
Protocol 확장을 통한 프로토콜 준수 (0) | 2023.06.23 |
---|---|
Delegation (0) | 2023.06.16 |
Extension (0) | 2023.06.08 |
Nested Types (0) | 2023.06.07 |
Type Casting (0) | 2023.06.07 |