Protocol
- 특정 역할을 수행하기 위한 메소드, 프로퍼티, 기타 요구사항 등의 청사진을 정의한다.
- 구조체, 클래스, 열거형은 프로토콜을 채택 (Adopt) 해서 특정 기능을 수행하기 위한 프로토콜의 요구사항을 실제로 구현할 수 있다.
- 어떤 프로토콜의 요구사항을 모두 따르는 것을 그 프로토콜을 준수 (Conform) 한다고 표현한다.
- 프로토콜의 요구사항을 충족시키려면 프로토콜이 제시하는 청사진의 기능을 모두 구현해야 한다.
- 프로토콜은 기능을 정의하고 제시할 뿐이지 기능을 구현하지는 않는다.
프로토콜 정의
protocol MyProtocol {
}
프로토콜 채택
struct MyStruct : MyProtocol {
}
class MyClass : MyProtocol {
}
enum MyEnum : MyProtocol {
}
- [코드 2] : 'MyStruct' 구조체, 'MyClass' 클래스, 'MyEnum' 열거형 모두 'MyProtocol' 프로토콜을 채택했다.
- 다른 클래스를 상속받는 동시에 프로토콜을 채택하는 클래스를 만들 때는 상속받을 클래스 이름 먼저 작성하고, 그 뒤에 채택할 프로토콜 이름을 작성하면 된다.
프로퍼티 요구
- 프로토콜은 자신을 채택한 타입이 어떤 프로퍼티를 구현해야 하는지 요구할 수 있다.
- 프로토콜을 채택한 타입은 프로토콜이 요구하는 프로퍼티의 이름과 타입만 맞게 구현해주면 된다.
- 프로퍼티를 읽기만 가능하도록 할지, 읽기 & 쓰기 모두 가능하도록 할지는 프로토콜이 정해야 한다.
- 프로토콜의 프로퍼티 요구사항은 항상 var 키워드를 사용한 변수 프로퍼티로 정의된다.
- 읽고 쓰기 모두 가능한 프로퍼티는 프로퍼티 정의 뒤에 { get set } 이라고 써주고, 읽기만 가능한 프로퍼티는 프로퍼티 정의 뒤에 { get } 이라고 써주면 된다.
protocol MyProtocol {
var readAndWriteProperty : String { get set }
var readOnlyProperty : String { get }
}
- [코드 3] : 'readAndWriteProperty' 프로퍼티는 읽고 쓰기 모두 가능하도록 정의되었고, 'readOnlyProperty' 프로퍼티는 읽기만 가능하도록 정의되었다.
protocol MyProtocol {
var readAndWriteProperty : String { get set }
}
class MyClass : MyProtocol {
var readAndWriteProperty : String
}
- [코드 4] : 'readAndWriteProperty' 프로퍼티가 프로토콜 안에 정의되었기 때문에 그 프로토콜을 채택한 'MyClass' 클래스는 반드시 'readAndWriteProperty' 프로퍼티를 선언해주어야 한다.
메소드 요구
- 프로토콜은 특정 인스턴스 메소드나 타입 메소드를 요구할 수도 있다.
- 프로토콜이 요구할 메소드는 프로토콜 정의에서 작성하는데, 메소드의 실제 구현부 ('{}') 는 제외하고 메소드의 이름 & 매개변수 & 반환 타입 등만 작성한다.
- 프로토콜의 메소드 요구에서는 매개변수 기본값을 지정할 수 없다.
protocol Information {
var name : String { get set }
var age : Int { get set }
func printMyInformation(name : name, age : age)
}
struct MyInformation : Information {
var name : String
var age : Int
func printMyInformation(name : name, age : age) {
print("Name = \(name), Age = \(age)")
}
}
이니셜라이저 요구
- 프로토콜은 특정한 이니셜라이저를 요구할 수도 있다.
- 프로토콜에서 이니셜라이저를 요구하려면 메소드 요구와 마찬가지로 이니셜라이저를 정의만 해놓고, 구현은 하지 않는다. (이니셜라이저의 매개변수를 지정만 해놓고, 중괄호로 구현부를 만들지는 않는다.)
protocol Communication {
var talker : String { get set }
func talk(to : Information)
init(talker : String, listener : String)
}
struct Information : Communication {
var talker : String
var listener : String
func talk(information : Information) {
print("\(talker) 이 \(information.listener) 에게 말하는중 ~")
}
init(talker : String, listener : String) {
self.talker = talker
self.listener = listener
}
}
let r1verfuture : Information = Information(talker : "r1verfuture", listener : "whatso")
let whatso : Information = Information(talker : "whatso", listener : "r1verfuture")
r1verfuture.talk(to : whatso)
프로토콜의 채택
- 프로토콜은 하나 이상의 프로토콜을 채택받아 기존 프로토콜의 요구사항보다 더 많은 요구사항을 추가할 수 있다.
- 프로토콜 채택 문법은 클래스의 상속 문법과 비슷하다.
protocol Readable {
func read()
}
protocol Writeable {
func write()
}
protocol ReadSpeakable : Readable {
func speak()
}
protocol ReadWriteSpeakable : Readable, Writeable {
func speak()
}
class Able : ReadWriteSpeakable {
func read() {
print("I am reading !")
}
func write() {
print("I am writing !")
}
func speak() {
print("I am speaking !")
}
}
참고