23 April 2017

Swift에서는 프로토콜 지향 프로그래밍을 지원하는 언어로, Protocol에 변수, 함수를 규약합니다.

protocol A {
    var name: String { get set }
    mutating func set(name: String)
}

위의 A라는 프로토콜은 변수 name와 함수 set(name:)이 선언되어 있습니다. 프로토콜 A를 따르는 타입은 변수 name, 함수 set(name:)이 반드시 정의된다고 볼 수 있으므로, 프로토콜 A를 확장(extension)할 수 있습니다.

extension A {
    mutating func set(name: String) {
        self.name = name
    }
}

변수 name의 타입은 String이므로, 동적으로 타입이 변할 수 없습니다. name의 타입을 동적으로 변하도록 하려면 Associated Type를 이용할 수 있습니다.

protocol A {
    associatedtype T
    var name: T { get set }
}

extension A {
    mutating func set(name: T) {
        self.name = name
    }
}

associatedtype은 하나 이상 프로토콜에 관련있는 타입에 이름을 지정합니다. 위에서 타입 T인 name은 하나 이상의 프로토콜을 따르므로, 프로토콜에 정의된 변수 또는 함수를 사용할 수 있습니다.

protocol B {}
extension B {
    var description: String {
        return "Hello world"
    }
}

protocol A {
    associatedtype T: B
    var name: T { get set }
}

extension A {
    mutating func set(name: T) {
        self.name = name
    }
    
    var description: String {
        return name.description
    }
}

변수 name은 타입 T이고, T는 프로토콜 B를 따르기 때문에 name은 프로토콜 B의 description을 사용할 수 있습니다. 그리고 프로토콜 B, C를 동시에 따르는 타입으로도 선언할 수 있습니다.

protocol B {}
extension B {
    var description: String {
        return "Hello world"
    }
}
protocol C {}
extension C {
    var debug: String {
        return "Debug"
    }
}

protocol A {
    associatedtype T: B, C
    var name: T { get set }
}

extension A {
    mutating func set(name: T) {
        self.name = name
    }
    
    var description: String {
        return name.description
    }
    var debug: String {
        return name.debug
    }
}

타입 T는 프로토콜 B, C를 따르므로 프로토콜 B의 description과 프로토콜 C의 debug를 변수 name에서 접근할 수 있습니다.


타입 Int를 프로토콜 B, C를 따르는 타입으로 확장합니다.

extension Int: B, C {}

프로토콜 A를 따르는 타입은 다음과 같이 선언할 수 있습니다.

struct AA: A {
    var name: Int
}

print(AA(name: 10).debug)

따라서 associatedtype을 잘 이용하면 Protocol Extension에서 거의 모든 것을 만들고, 해당 프로토콜을 따르기만 하는 타입을 선언만 하면 됩니다.