swift & iOS/swift

[swift] 프로토콜 protocol

whale3 2022. 1. 31. 20:37

프로토콜이 좀 생소해서 항상 챙겨보고 있는 아래 유튜브 영상을 많이 참고했다. 아 물론 swift 공식문서도...

https://www.youtube.com/watch?v=p19mUgg1CFQ&list=PLJqaIeuL7nuFbWKMhG8-xLzF1T7gIPr8Z&index=69

 


프로토콜?

프로토콜은 특정 클래스와 관련 없는 하나의 기능이나 임무를 수행하는데 필요한 프로퍼티와 메소드 선언부를 모아놓은 것이다. 프로토콜에 선언된 메소드에 대한 구현은 이 프로토콜을 채택(adopt)한 클래스, 구조체, 열거형에서 구현해야 한다 (conform: 준수하다). 그리고 프로토콜도 다른 클래스나 구조체, enum처럼 타입의 한 종류이다.

2022.02.19 보충: protocals are a way to express an API more concisely

 

 

프로토콜을 사용해서 좋은 점

참고: https://youtu.be/Y8ss6118RQY?list=PL3d_SFOiG7_8ofjyKzX6Nl1wZehbdiZC_&t=444

자격 제한을 둘 수 있음(mandating behavior) - dictionary의 key는 hashable 프로토콜을 준수하는 타입이어야 한다. 

다른 타입 간에 기능을 공유할 수 있음(sharing funtionality in disperate types) - 어떤 프로토콜을 채택하면 그것을 준수해야 하기 때문

뷰가 특정 컨트롤러에 대한 정보가 없어도 뷰~컨트롤러 사이의 커뮤니케이션이 가능함 - delegate 패턴 (~Delegate, ~DataSource로 끝나는 프로토콜들), 뷰는 특정 컨트롤러에 대한 정보를 갖고 있지 않기 때문에 재사용도 가능함

 

 

POP(protocal oriented programming)

프로토콜 단위로 묶어 표현하고 extension으로 기본적인 것을 구현하여 단일 상속의 한계를 극복하고자 하는 프로그래밍 기법이라고 한다. 아직은 좀 생소한데 나중에 좀 더 개념이 정리 되면 이 부분은 다시 작성해야 할 것 같다. 그래도 단일 상속의 한계는 약간 알 것 같기도 하다. 일단 '상속'은 클래스에서만 가능하기도 하고 (구조체나 enum은 어떡해,,) 클래스를 상속하면 자식 클래스(subclass)가 부모 클래스(super class)의 모든 것을 상속하게 되는데 그 중에 subclass에 맞지 않거나 해당하지 않는 것이 있을 수도 있을 것 같다. 이럴 때 protocol을 활용하는 거구나 하는 느낌은 받았다. 

 

프로토콜 만들기

프로토콜 내부에 필요한 프로퍼티나 메소드(선언부)를 작성하면 된다. 프로퍼티는 stored property인지 computed property인지는 구현할 때 정하면 된다. 메소드는 ... 로 여러 개의 파라미터(variadic parameters)를 받는 메소드는 작성할 수 있지만 파라미터의 디폴트 값을 프로토콜에서 정할 수는 없다. 프로토콜도 '상속' 개념이 있고 여러 개의 프로토콜을 상속할 수 있다. 아래의 MyProtocol을 채택한다면 이 MyProtocol은 물론,  MyProtocol이 상속하는 나머지 2개의 프로토콜도 준수해야 한다. 

 

protocal MyProtocal: InheritProtocol1, InheritProtocol2 {
    // 프로퍼티 이름
    // 메소드 선언부

    var firstName: String { get set } // 읽기 가능 쓰기 가능

    func getFullName() -> String

    optional func shoutOut() // 필요할 때만 구현하면 되는 메소드
}

 

그리고 값 타입인 인스턴스(구조체 struct, 열거형 enum)의 메소드 중에 인스턴스나 그 프로퍼티를 수정하려면 func 앞에 mutating 키워드를 붙여야 했는데, 프로토콜도 마찬가지로 필요한 경우에는 func 앞에 mutating 붙여서 선언해 놓으면 된다. 이 프로토콜을 클래스에서

채택하여 구현할 경우에는 mutating 키워드 필요없다. mutating 키워드는 struct, enum에서만 사용되기 때문이다. 

 

// 출처: https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID271

protocol Togglable {
    mutating func toggle()
}

enum OnOffSwitch: Togglable {
    case off, on
    
    mutating func toggle() {
        switch self {
        case .off:
            self = .on
        case .on:
            self = .off
        }
    }
}
var lightSwitch = OnOffSwitch.off
lightSwitch.toggle() // lightSwitch는 이제 .on이 되었음

 

그리고 init이 들어있는 프로토콜을 클래스가 채택할 경우 클래스 내의 그 init 앞에 required 키워드를 붙여야함. 

 

프로토콜에 대해 쓸 내용이 또 생기면 추가로 포스팅 해야겠다. 

그리고 프로토콜에 항상 따라오는 delegate 패턴이 있던데 이건 다음 포스팅에...

 

반응형