[Swift 정면돌파] 14. 프로토콜

H43RO·2021년 8월 8일
2

Swift 정면돌파

목록 보기
14/19
post-thumbnail

오늘은 POP 패러다임을 차용한 언어인 스위프트의 꽃, 프로토콜에 대하여 공부해보았다.

프로토콜 개념

  • 프로토콜(Protocol) 은 특정 역할을 수행하기 위한 메소드, 프로퍼티, 요구사항 등의 청사진을 정의함
  • 구조체, 클래스, 열거형은 프로토콜을 채택(Adopted) 해서 특정 기능을 수행하기 위한 프로토콜의 요구사항을 실제로 구현할 수 있음 → 프로토콜을 준수(Conform) 한다고 표현
  • 타입에서 프로토콜의 요구사항을 충족시키려면 프로토콜이 제시하는 청사진의 기능을 모두 구현해야 함.
    즉, 프로토콜은 기능을 정의하고 제시 할 뿐이지 스스로 기능을 구현하지는 않음 (인터페이스와 유사)

프로토콜 구현

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
profile
어려울수록 기본에 미치고 열광하라

0개의 댓글