본문 바로가기
문법관련/Swift

Protocol (Yagom)

by print_soo 2022. 6. 1.

프로토콜

프로토콜은 특정 역할을 수행하기 위한 메서드, 프로퍼티, 이니셜라이저등의 요구사항을 정의한다.  (특정 기능이나 속성에 대한 설계도)

쉽게 말하면, 어떤 타입(구조체, 클래스, 열거형)에 "너는 이 기능이 꼭 필요해. 그러니깐 이 기능을 꼭 구현해!" 라고 강요하는 것과 같다.

 

구조체, 클래스, 열거형은 프로토콜을 채택해서 프로토콜의 요구사항을 실제로 구현할 수 있다.

(여기서 채택이란, 어떤 타입이 "나는 이 기능을 수행할거야" 라고 말하는 것)

 

 

 

프로토콜의 정의

protocol 프로토콜 이름 {
	// 정의부
}

 

예시를 통해서 살펴보자. 

//말할 수 있다 라는 기능을 프로토콜로 나타낸 것
protocol Talkable {
    var topic: String { get set }
    var launguage: String { get }
    
    func talk()
    
    init(topic: String, launguage: String)
}

 

어떤 타입이 Talkable이라는 프로토콜이 채택이 되었을 때, 해당 타입은 topic, launguage라는 프로퍼티와 talk라는 메서드와

init(topic: String, launguage: String) 이니셜라이저를 구현해야한다! 라는 의미이다. 

 

💡  우리가 실제로 클래스, 구조체, 열거형같은 타입에서는 프로퍼티나 메서드의 내용을 구현해주었지만 프로토콜에서는 내용을 구현하는 것이 아니라 어떤 프로퍼티, 메서드, 이니셜라이저가 필요한지를 알려주는 것이다 

 

 

프로퍼티 요구

1. 프로퍼티 요구는 항상 var 키워드를 사용해야한다.
2. 연산  프로퍼티의 경우 읽기 전용인지 쓰기 읽기 전용인지 set과 get을 통해서 나타내어야한다. 
(get: 
읽기 전용, set: 읽기 쓰기 전용)

 

 

 

프로토콜 채택 및 준수

프로토콜을 채택하는 과정은 타입뒤에 :(콜론)을 작성하고 그 뒤에 프로토콜 이름을 작성하면된다. 

또한 프로토콜을 준수하는 과정은 해당 타입안에 프로토콜에서 작성된 프로퍼티나 메서드를 작성하는 것을 의미한다.

 

struct Person: Talkable {
    // 프로퍼티 요구 준수
    var topic: String
    var language: String
    
    // 메서드 요구 준수
    func talk() {
        print("\(topic)에 대해 \(language)로 말합니다")
    }

    // 이니셜라이저 요구 준수
    init(topic: String, language: String) {
        self.topic = topic
        self.language = language
    }
}

 

  • 읽기전용 프로퍼티 요구는 연산 프로퍼티로 대체가 가능하다. 
var launguage: String // 읽기 전용 프로퍼티

var language: String { return "한국어" } // 연산 프로퍼티

 

  • 읽기, 쓰기 프로퍼티도 연산 프로퍼티로 대체가 가능하다.
var topic: String { get set } // 읽기, 쓰기 프로퍼티

var subject: String = ""
var topic: String { // 연산 프로퍼티
    set {
        self.subject = newValue
    }
    get {
         return self.subject
    }
}

 

 

 

프로토콜 상속

프로토콜은 클래스와 다르게 다중 상속이 가능하다.

 

protocol 프로토콜 이름: 부모 프로토콜 이름 목록 {
	// 정의부
}

 

 

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() { }
}

 

 

 

프로토콜이 가지는 의미

 

프로토콜의 입장에서 볼 때 "넌 꼭 이걸 해야한다"라고 강요한다고 볼수 있지만 프로토콜을 사용하는 입장에서는 해당 프로토콜을 준수하고 있기 때문에 어떤 기능을 구현했는지 좀더 명확하게 알 수 있다.