Day 12 - 2023.01.18
스위프트의 프로토콜은 다른 언어에서의 추상 클래스 혹은 인터페이스와 동치하여 생각하면 안된다.
프로토콜은 특정 역활을 수행하기 위한 메서드, 프로퍼티, 기타 요구사항을 정의한다.
(어떤 타입: 구조체나 클래스나 열거형에다가 기능을 담는것을 요구하는 것과 같음)
구조체, 클래스, 열거형은 프로토콜을 채택(Adopted)해서 프로토콜의 요구사항을 실제로 구현할 수 있다.
어떤 프로토콜의 요구사항을 모두 따르는 타입은 그 프로토콜을 준수한다(Conform)고 표현한다.
타입에서 프로토콜의 요구사항을 충족시키려면 프로토콜이 제시하는 기능을 모두 구현해야 한다. 즉, 프로토콜은 기능을 정의하고 제시 할 뿐이지 스스로 기능을 구현하지는 않는다.
protocol 프로토콜 이름 {
/* 정의부 */
}
<<프로퍼티 요구>>
protocol Talkable {
// 프로퍼티 요구
var topic: String { get set }
var language: String { get }
// 메서드 요구
func talk()
// 이니셜라이저 요구
init(topic: String, language: String)
}
// Person 구조체는 Talkble 프로토콜을 채택했다.
struct Person: Talkable {
// 프로퍼티 요구 준수
var topic: String
let language: String
// 읽기전용 프로퍼티 요구는 연산 프로퍼티로 대체가 가능하다.
// var language: String { return "한국어" }
// 물론 읽기, 쓰기 프로퍼티도 연산 프로퍼티로 대체할 수 있다.
// var subject: String = ""
// var topic: String {
// sef {
// self.subject = newValue
// }
// get {
// return self.subject
// }
// }
// 메서드 요구 준수
func talk() {
print("\(topic)에 대해 \(language)로 말한다.")
}
// 이니셜라이저 요구 준수
init(topic: String, language: String) {
self.topic = topic
self.language = laguage
}
}
프로퍼티 요구는 다양한 방법으로 해석 및 구현 할 수 있다.
struct Person: Talkable {
var subject: String = ""
// 프로퍼티 요구는 연산 프로퍼티로 대체가 가능하다.
var topic: String {
sef {
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 프로토콜 이름: 부모 프로토콜 이름 목록 {
/* 정의부 */
}
protocol Readable {
func read()
}
protocol Writeable {
func write()
}
protocol ReadSpeakable: Readalbe {
func speak()
}
protocol ReadWriteSpeakable: Readable, Writeable {
func speak()
}
struct SomeType: ReadWriteSpeakable {
func read() {
print("Read")
}
func write() {
print("Write")
}
func speak() {
print("Speak")
}
}
<< 클래스 상속과 프로토콜 >>
클래스에서 상속과 프로토콜 채택을 동시에 하려면 클래스를 먼저 명시하고 그 뒤에 채택할 프로토콜 목록을 작성합니다.
calss SuperClass: Readable {
func read() {}
}
class subClass: SuperClass, Writealbe, 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()
} // 출력 : 동작하지 않음
somAny = sun
if let someReadable: Readable = someAny as? Readanle {
someReadanle.read()
} // 출력 : read