이번에는 프로토콜에 대해 알아보려고 한다. 사실 swift에서 매우 중요한 개념이기 때문에 이번 책을 통해 프로토콜에 대해 통달했다는 생각하지 않고, 그냥 이러한 개념이구나라는 정도로 알았습니다.
특정 역할을 하기 위한 메소드 ,프로퍼티, 기타 요구사항 등의 청사진을 정의
-> 특정 역할을 하기 위해 필요한 것들을 정의해놓은 규범
프로토콜을 채택해서 특정 기능을 실행하기 위한 프로토콜의 요구사항을 실제로 구현할 수 있음
‘프로토콜을 준수한다’ → 프로토콜의 요구사항을 모두 따름
프로토콜은 정의를 하고 제시를 하는 것이지, 스스로가 기능을 구현하는 것은 아님!
프로토콜은 쉼표를 통해 여러 개 채택 가능
struct SomeClass: SuperClass, AProtocol, AnotherProtocol {
}
프로퍼티 요구
protocol SomeProtocol {
var settableProperty: String { get set }
var notNeedToBeSettableProperty: String { get }
}
메소드 요구
//무언가를 수신받을 수 있는 기능
protocol Receivable {
func received(data: Any, from: Sendable)
}
//무언가를 발신할 수 있는 기능
protocol Sendable {
var from: Sendable { get }
var to: Receivable? { get }
func send(data: Any)
static func isSendableInstance(_ instance: Any) -> Bool
}
//수신,발신이 가능한 Message 클래스
class Message: Sendable, Receivable {
//발신은 Sendable 프로토콜을 준수하는 타입의 인스턴스여야 함
var from: Sendable {
return self
}
//상대방은 Receivable 프로토콜을 준수하는 타입의 인스턴스여야 함
var to: Receivable?
//메세지 발신
func send(data: Any) {
guard let receiver: Receivable = self.to else {
print("Message has no receiver")
return
}
//수신 가능한 인스턴스의 received 메소드 호출
receiver.received(data: data, from: self.from)
}
//메세지 수신
func received(data: Any, from: Sendable) {
print("Message received \(data) from \(from)")
}
//class 메소드로 상속 가능
class func isSendableInstance(_ instance: Any) -> Bool {
if let sendableInstance: Sendable = instance as? Sendable {
return sendableInstance.to != nil
}
return false
}
}
//수신, 발신이 가능한 Mail 클래스
class Mail: Sendable, Receivable {
var from: Sendable {
return self
}
var to: Receivable?
func send(data: Any) {
guard let receiver: Receivable = self.to else {
print("Mail has no receiver")
return
}
receiver.received(data: data, from: self.from)
}
func received(data: Any, from: Sendable) {
print("Mail received \(data) from \(from)")
}
//static 메소드로 상속 불가
static func isSendableInstance(_ instance: Any) -> Bool {
if let sendableInstance: Sendable = instance as? Sendable {
return sendableInstance.to != nil
}
return false
}
}
//두 Message 인스턴스를 생성
let myPhoneMessage: Message = Message()
let yourPhoneMessage: Message = Message()
//아직 수신받을 인스턴스가 없다
myPhoneMessage.send(data: "Hello") //Message has no receiver
//수신받을 인스턴스가 있어서 메세지를 주고받을 수 있음
myPhoneMessage.to = yourPhoneMessage
myPhoneMessage.send(data: "Hello") //Message received Hello from Message
이니셜라이저 요구
protocol Named {
var name: String { get }
init(name: String)
}
struct Pet: Named {
var name: String
init(name: String) {
self.name = name
}
}
class Person: Named {
var name: String
required init(name: String) { //class에서 이니셜라이저가 필요하기 때문에 required를 붙임
self.name = name
}
}
class School {
var name: String
init(name: String) {
self.name = name
}
}
class MiddleSchool: School, Named {
required override init(name: String) { //이미 School에서 정의가 되어 있어서 override 작성
super.init(name: name)
}
}
프로토콜 상속
프로토콜 조합과 프로토콜 준수 확인
protocol: Named {
var name: String { get }
}
protocol: Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}
func celebrateBirthday(to celebrator: Named & Aged) { //&를 사용하여 프로토콜 사용
print("Happy Birthday \(celebrator.name)! Now you are \(celebrator.age)")
}
let ted: Person = Person(name: "Ted", age: 26) //이렇게해서 &를 사용하지 않고도 가능
celebrateBirthday(to: ted)
프로토콜의 선택적 요구
위임을 위한 프로토콜
애플의 프레임워크에서 중요한 패턴 중 하나
ex. UITableView 타입의 인스턴스가 해야 하는 일을 위임받아 처리하는 인스턴스는 UITableViewDelegate 프로토콜을 준수함
UITableViewDelegate 프로토콜을 준수하는 인스턴스는 UITableView의 인스턴스가 해야 하는 일을 대신 처리해 줌
한 문장으로 정리하면 프로토콜은 어떠한 규약을 정해놓고 그 규약을 채택하는 것? 정도로 생각하면 될 것 같다. Delegate pattern은 예전에 사용했던 것 같은데, 이에 대해서도 나중에 다시 공부해야겠다.