[Swift] 프로토콜

선주·2022년 4월 11일
0

Swift

목록 보기
12/20

📌 프로토콜

프로토콜은 특정 역할을 수행하기 위한 메서드, 프로퍼티, 기타 요구사항 등의 청사진을 정의한다.

구조체, 클래스, 열거형은 프로토콜을 채택(Adopted)해서 특정 기능을 수행하기 위한 프로토콜의 요구사항을 실제로 구현할 수 있다.


프로토콜이 갖는 의미

프로토콜 사용자의 입장에서, 이 타입은 이 프로토콜을 준수하고 있기 때문에 이런 기능을 다 수행할 수 있겠구나~ 하는 것을 명확히 한다.


프로토콜 정의

protocol Talkable {
    
    // 프로퍼티 요구
    var topic: String { get set }
    var language: String { get }
    
    // 메서드 요구
    func talk()
    
    // 이니셜라이저 요구
    init(topic: String, language: String)
}
  • 프로퍼티 요구
    • 항상 var 키워드를 사용한다.
    • get읽기만 가능해도 상관 없다는 뜻이며, getset을 모두 명시하면 읽기와 쓰기 모두 가능한 프로퍼티라는 뜻이다.

프로토콜 채택

변수 language는 프로토콜 정의에 의해 읽기 전용이므로 읽기만 가능한 let으로 구현해줘도 되지만, var도 읽기가 가능하므로 var로 구현해줘도 된다.

struct Person: Talkable { // 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
    }
}

프로토콜 상속

프로토콜은 클래스와 상속 문법이 유사하지만 클래스와 다르게 다중상속이 가능하다.

protocol Readable {
    func read()
}
protocol Writeable {
    func write()
}
protocol ReadSpeakable: Readable {
    func speak()
}
protocol ReadWriteSpeakable: Readable, Writeable {
    func speak()
}

아래의 SomeType 구조체처럼 ReadWriteSpeakableReadableWritable을 상속받기 때문에 이 프로토콜을 채택한 구조체는 read(), write(), 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 연산자를 사용해 인스턴스가 특정 프로토콜을 준수하는지 확인할 수 있다.

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

또는 딕셔너리에서 값을 꺼냈거나 Any타입으로 값을 받아왔거나 한다면 이런 식으로 as 연산자를 활용해 타입캐스팅해서 사용할 수 있다.

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개의 댓글