BOID
[swift] 프로토콜(protocol)에대해 파해치기 (2 / 2) - HoonIOS 본문
안녕하세요 HoonIOS입니다.
저번에 프로토콜에 대해 포스팅을 했는데요 한 페이지에 하면 양도 너무 많아서 두 개로 나눴습니다.
이번 포스팅에서는 이니셜라이저 상속, 여러 프로토콜의 상속, 매개변수값에 프로토콜을 상속, optional프로토콜에 대해 포스팅하려고 합니다.
프로토콜에 이니셜라이저 구현
이니셜라이저도 프로토콜에 구현을 할 수 있습니다.
메서드랑 같은 형식으로 이니셜라이저의 매개 변수만 지정하고 나머지 중괄호의 코드값들은 지정을 하지 않습니다.
이니셜라이저에서 주의해야 할 점은 구조체 이니셜라이저는 상속이 없기 때문에 이니셜라이저 요구에 크게 신경을 쓸 필요는 없지만 클래스는 그것이 아닙니다.
여기서 클래스는 이니셜라이저가 지정인 편의 이니셜라이저인지는 중요하지 않습니다. 이니셜라이저 요구에 부합하는 이니셜라이저를 구현을 할때는 required 식별자를 붙인 요구 이니셜라이저로 구현을 해줘야 합니다.
아래 구조체와 클래스에서 이니셜라이저 요구사항을 정의한 예시를 한번 살펴보겠습니다.
* 코드 설명
- test에 이니셜라이저를 지정해줬습니다.
- struct(구조체)를 보면은 있는 그대로 요구사항 이니셜라이저를 구현해줬습니다.
- class(클래스)를 보면은 요구사항 이니셜라이저를 구현할 때 앞에 required를 붙여줘야 합니다.
그렇다고 무작정 클래스다 하고 보이면 requried를 붙여주라는것은 아닙니다. 붙이지 않아도 될 때도 있는데요 바로 클래스가 더 이상 상속을 받을 수 없는 final클래스이면 따로 요청 required를 안 붙여줘도 됩니다.
만약 프로토콜이 요구하는 이니셜라이저가 이미 구현되어 있는 상태에서 그 클래스를 상속받으면 이니셜라이저를 구현해줬을 때 required override를 꼭 명시해줘야 합니다.
* 코드 설명
- classPerson클래스에 test프로토콜을 구현받았지 않았지만 이미 해당 클래스 안에 test 프로토콜에 해당하는 변수랑 이니셜라이저가 정의되어 있습니다.
이니셜라이저는 이뿐만 아니라 일반 이니셜라이저 외에 실패 가능한 이니셜라이저도 구현을 할 수 있습니다.
만약 프로토콜에 실패 가능한 이니셜라이저를 구현해줬어도 클래스, 구조체에 구현을 해줄 때 일반 이니셜라이저로 구현을 해도 무방합니다.
프로토콜 간에 상속 구현
프로토콜은 하나 이상의 프로토콜을 상속받아서 더 많은 요구사항을 구현할 수 있습니다.
쉽게 말해 클래스의 상속과 비슷하다고 생각을 하시면 될꺼같습니다.
* 코드 설명
- who의 프로토콜, test 프로토콜을 따로 구현해줬고 이것을 클래스에 하나씩 구현을 해줬습니다.
이제 일반적인 구현 말고 who프로토콜을 test 프로토콜에 상속을 시켜서 구현해보겠습니다.
* 코드 설명
- 위 방식과는 다른 게 who의 프로토콜을 test 프로토콜에 상속을 시켜줬습니다.
- who 프로토콜을 상속받은 test프로토콜을 exam에 상속을 시켜줘서 클래스에 구현을 해줬습니다.
- 따라서 해당 프로토콜을 상속받은 exam 클래스는 두 프로토콜에서 구현해준 변수, 이니셜라이저, 메서드를 모두 구현해줘야 합니다.
만약에 프로토콜의 상속 리스트에 class키워드를 추가해주면 해당 프로토콜은 클래스 타입에서만 채택될 수 있도록 제한을 두게 됩니다.
* 코드 설명
- 위 코드를 보면 test 프로토콜에 class를 구현해줘 해당 프로토콜은 이제 클래스에서만 구현이 되게 됩니다.
- 따라서 이 프로토콜을 구조체인 sample에 구현을 시키면 에러가 발생하게 됩니다.
- 참조하실 내용이 있는데요 test 구현해준 class는 AnyObject로 대신해도 됩니다. 즉 class = AnyObject는 같은 말을 뜻합니다.
프로토콜 조합과 매개변수의 조합
하나의 매개변수에 여러 개의 프로토콜을 준수하는 타입이라면 하나의 프로토콜을 한 번에 조합을 해서 요구를 할 수 있습니다.
다시 말해서 하나의 매개변수에 프로토콜 두 개를 요구할 수 있는데 바로 & ( 앰버서드 )를 프로토콜 이름 사이에 넣어주면 됩니다.
야곰님 책에 있는 예시를 보고 한번 설명을 해보겠습니다.
* 코드 설명
- celebrateBirthday 메서드의 매개변수를 보면 두 개의 프로토콜을 조합해서 요구하고 있습니다.
- 이 말인 즉 두 개의 프로토콜을 구현한 클래스. 구조체에서만 해당 메서드를 구현하고 실행할 수 있다는 뜻이 됩니다.
- 밑에 mycar객체를 매개변수에 넣어 celebrateBirthday 메서드를 실행시켰는데 Car 클래스는 Named밖에 프로토콜 구현을 하지 않아 에러가 발생을 합니다.
- Person 구조체는 Named, Aged 프로토콜 모두 구현하고 있으므로 해당 객체를 매개변수에 넣어 메서드를 실행시키면 에러가 발생하지 않는 것을 확인할 수 있습니다.
- 또 변수에 프로토콜 조합을 할 수 있는데 someVariable 변수를 보면 한 타입만 조합할 수 있고 그이 상부 터는 에러가 발생하는 것을 확인할 수 있습니다.
Optional 프로토콜의 선택적 요구에 대해
프로토콜의 요구사항 중에서 몇 개를 선택적으로 구현하게 요구를 지정할 수 있습니다.
델리게이트 메서드 같은 곳에서 많이 볼 수 있는 것이에요!
(사실 제가 프로토콜 다시 공부한 이유이기도 합니다.ㅎ)
선택적 요구사항을 정의하고 싶은 프로토콜은 앞에 objc속성을 부여해준 프로토콜이어야 합니다.
프로젝트를 Objective-C 코드와 공유를 하고 있지도 않고 싶지도 않아도 objc속성이 부여되어야만 선택적 요구사항을 정의를 할 수 있습니다.
objc가 부연된 프로토콜은 클래스에서만 채택을 받을 수 있습니다. 즉 열거형이나 구조체 등에서 objc가 부여된 프로토콜을 아예 채택할 수 없습니다.
※ 알아두기
objc속성을 사용하려면 Foundation 프레임워크를 임포트 해야 됩니다.
메서드나 프로퍼티를 선택적 요구사항으로 요구를 하면 그 요구사항은 자동으로 옵셔널이 됩니다.
여기서 메서드의 반환이나 타입이 옵셔널 형태가 되는 게 아니라 메서드 자체의 타입이 옵셔널이 되는 것입니다.
예를 들어서 (type) -> type 이렇게 타입을 매개변수로 입력해 타입을 반환하는 메서드가 있으면 ((type) -> type)? 이렇게 메서드 자체의 옵셔널 타입이 된다는 것입니다.
한번 구현을 해보겠습니다.
* 코드 설명
- eat 프로토콜을 선택적 요구사항으로 정의하기 위해 protocol 앞에 @objc 속성을 부여해줬고 요구사항을 정의할 메서드에 @objc속성과 optional 속성을 부여해줘 선택적 요구사항을 구현해줬습니다.
- 실제 eat 프로토콜을 구현해준 fat과 thin의 클래스를 보면은 diet라는 선택적 요구사항 메서드를 fat에는 선언해주고 thin에는 선언을 해주지 않은 것을 볼 수 있습니다.
- eat 프로토콜 타입인 person 변수에 thin인스턴스인 GF를 넣어 줬습니다. 그리고 person이라는 인스턴스에 실제로 diet() 메서드가 구현되어 있는지 알 수가 없어 옵셔널 체인을 통해 diet() 메서드 호출을 시도해 보았지만 그 결과 아무 응답이 없는 것을 확인할 수 있었습니다.
이렇게 프로토콜의 다방적인 면에 대해서 포스팅을 해봤습니다. 코드를 구현하고 많은 애플 공식 문서를 보다 보면 protocol을 많이 보게 될 정도로 상당히 중요한 부분이니 보고 보고 또 봐야 될 거 같습니다. :)
'swift 시작기' 카테고리의 다른 글
[swift] 상속(Inheritance)에대해 뽀시자!!! (0) | 2021.05.07 |
---|---|
[swift] 프로토콜(protocol)에대해 파해치기 (1 / 2) - HoonIOS (0) | 2021.04.28 |
[swift] 고차함수(map, filter, reduce)란? (0) | 2021.04.14 |
[swift] 스위프트에서 메모리충돌 & 대처 - HoonIOS (0) | 2021.04.11 |
[swift] 후처리 defer란? - HoonIOS (0) | 2021.04.08 |