오늘은 POP 패러다임을 차용한 언어인 스위프트의 꽃, 프로토콜에 대하여 공부해보았다.
protocol Talkable {
// 프로퍼티 요구 (항상 var 키워드 사용)
// get 은 읽기만 가능해도 상관없다는 거고, set 까지 명시하면 읽기 쓰기 모두 가능한 프로퍼티여야 함
var topic: String { get set }
var language: String { get }
// 메소드 요구
func talk()
// 이니셜라이저 요구
init(topic: String, language: String)
}
// Person 구조체는 Talkable 프로토콜을 채택한 것임
struct Person: Talkable {
// 프로퍼티 요구 준수
var topic: String
let language: String
// 읽기전용 프로퍼티 요구는 연산 프로퍼티로 대체 가능
// var language: String { return "한국어" }
// 읽기 쓰기 프로퍼티도 연산 프로퍼티로 대체할 수 있음
// var subject: String = ""
// var topic: String {
// set {
// self.subject = newValue
// }
// get {
// return self.subject
// }
// }
// 메소드 요구 준수
func talk() {
print("\(topic)에 대해 \(language)로 말합니다")
}
// 이니셜라이저 요구 준수
init(topic: String, language: String) {
self.topic = topic
self.language = language
}
}
struct Person: Talkable {
var subject: String = ""
var topic: String {
set {
self.subject = newValue
}
get {
return self.subject
}
}
var language: String { return "한국어" }
func talk() {
print("\(topic)에 대해 \(language)로 말합니다")
}
init(topic: String, language: String) {
self.topic = topic
}
}
→ 프로토콜은 하나 이상의 프로토콜을 상속받아
더 많은 요구사항을 추가할 수 있음 (다중 상속 가능)
protocol Readable {
func read()
}
protocol Writeable {
func write()
}
protocol ReadSpeakable: Readable {
func speak()
}
protocol ReadWriteSpeakable: Readable, Writeable {
func speak()
}
struct SomeType: ReadWriteSpeakable {
func read() {
print("Read")
}
func write() {
print("Write")
}
func speak() {
print("Speak")
}
}
// 클래스에서 상속과 프로토콜 채택을 동시에 하려면
// 클래스명 명시 후 뒤에 채택할 프로토콜 목록 작성
class SuperClass: Readable {
func read() { }
}
class SubClass: SuperClass, Writeable, ReadSpeakable {
func write() { }
func speak() { }
}
→ is
, as
연산자를 사용하여 인스턴스가 특정 프로토콜을 준수하는지 확인 가능
let sup: SuperClass = SuperClass()
let sub: SubClass = SubClass()
var someAny: Any = sup
someAny is Readable // true
someAny is ReadSpeakable // false
someAny = sub
someAny is Readable // true
someAny is ReadSpeakable // true
someAny = sup
if let someReadable: Readable = someAny as? Readable {
someReadable.read()
} // read
if let someReadSpeakable: ReadSpeakable = someAny as? ReadSpeakable {
someReadSpeakable.speak()
} // 동작하지 않음
someAny = sub
if let someReadable: Readable = someAny as? Readable {
someReadable.read()
} // read