2016-11-05 2 views
4

다음과 같은 이유가 인쇄되어 있지 않은 이유가 궁금합니다.프로토콜 확장명 및 서브 클래스

/* Fails */ 
protocol TheProtocol { 
    func update() 
} 

class A: TheProtocol { 
} 

class B : A {} 

extension TheProtocol { 
    func update() { 
     print("Called update from TheProtocol") 
    } 
} 

extension TheProtocol where Self: B { 
    func update() { 
     print("Called update from B") 
    } 
} 

let instanceB = B() 
instanceB.update() 

let instanceBViaProtocol:TheProtocol = B() 
instanceBViaProtocol.update() 

이 인쇄됩니다 다음

Called update from B 
Called update from TheProtocol // Why not: Called update from B (extension) 

instanceBViaProtocol.update() 

이 TheProtocol에 확장()에서 업데이트를 실행하지 않는 이유는 특히 궁금 :

extension TheProtocol where Self: B { 
    func update() { 
     print("Called update from B") 
    } 
} 

나는 그것이 B는 TheProtocol을 채택한 A로부터 상속 받았기 때문에 B가 TheProtocol을 암묵적으로 채택 할 것이라고 생각합니다. 프로토콜 채택을 A에서 B로 이동하면 예상 결과가 나타납니다.

protocol TheProtocol { 
    func update() 
} 

class A { // Remove TheProtocol 
} 

class B : A, TheProtocol {} // Add TheProtocol 

extension TheProtocol { 
    func update() { 
     print("Called update from TheProtocol") 
    } 
} 

extension TheProtocol where Self: B { 
    func update() { 
     print("Called update from B") 
    } 
} 

let instanceB = B() 
instanceB.update() 

let instanceBViaProtocol:TheProtocol = B() 
instanceBViaProtocol.update() 

결과 :

Called update from B 
Called update from B 

나는 https://medium.com/ios-os-x-development/swift-protocol-extension-method-dispatch-6a6bf270ba94#.6cm4oqaq1http://krakendev.io/blog/subclassing-can-suck-and-heres-why에보고했다, 그러나 나는이 알아낼 수 없습니다. 확장 메소드는 프로토콜을 채택하는 엔티티의 서브 클래스에서 존중되지 않습니까?

+0

'확장 기능 TheProtocol 어디서 Self : B {'에서'확장 기능 TheProtocol where Self : A {'그리고 당신에게 뭔가 설명하는지보십시오. –

+0

팁 주셔서 감사. – user6902806

답변

0

대답은 방법 파견 + a Bug in Swift입니다.

메서드 디스패치는 메서드가 호출 될 때 실행할 구현을 선택하기 위해 컴파일러에서 사용되는 메커니즘입니다. Swift는 3 가지 방법으로 발송합니다. 그것에 대해 읽을 수 있습니다 here

발송 방법은 인스턴스의 유형이 아닌 참조 유형에 따라 결정됩니다. 귀하의 경우 참조 유형은 TheProtocol입니다.

let instanceBViaProtocol:TheProtocol = B() 
instanceBViaProtocol.update() 

요구 사항 방법에 대한 공통적 인 동작을 정의하는 프로토콜 확장이 있습니다. 이 경우 동적 디스패치가 사용됩니다. 이는 B에서 선언 한 구현을 사용해야 함을 의미합니다. 그러나이 문제를 일으키는 a bug in Swift이 있습니다.

각 유형별로 Swift는 감시 모니터를 사용하여 동적 디스패치에 사용되는 구현을 등록합니다. 이 버그로 인해 B 클래스는 TheProtocol의 Witness 테이블에 update() 구현을 등록하지 못하게됩니다. 그리고 TheProtocol 테이블을 통해 업데이트가 전달되면 잘못된 구현이 사용됩니다.

여기에 몇 가지 변경 사항이 포함되어 있습니다. 수퍼 클래스에서 업데이트를 선언하고 서브 클래스에서이를 재정의하면 예상대로 작동합니다. 그게 나에게 벌레를 보는 가장 깨끗한 방법이야.

protocol TheProtocol { 
    func update() 
} 

class A: TheProtocol { 
    func update(){ 
     print("Implementation of A") 
    } 
} 

class B : A { 
    override func update(){ 
     print("Implementation of B") 
    } 
} 

//All those who conform to TheProtocol will execute this. 
extension TheProtocol { 
    func update() { 
     print("Common: TheProtocol") 
    } 
} 
extension TheProtocol where Self: B { 
    func update() { 
     print("Common: TheProtocol for B's") 
    } 
} 
extension TheProtocol where Self: A { 
    func update() { 
     print("Common: TheProtocol for A's") 
    } 
} 


let instanceBViaProtocol:TheProtocol = B() //It prints "Implementation of B" 
instanceBViaProtocol.update() 

이 답변을 보내 주시면 감사하겠습니다.

https://www.raizlabs.com/dev/2016/12/swift-method-dispatch/에는 신속한 방법 발송에 대한 멋진 설명이 있습니다.

Here 당신은 프로토콜 확장에서 메소드 디스패치에 관해 쓴 짧은 것을 읽을 수 있습니다.

관련 문제