2014-09-15 3 views
6

Swift에서 제네릭의 미묘한 부분을 이해하는 데 여전히 문제가 있습니다. 나는 다음과 같은 유형을 정의 :유형이 프로토콜을 준수하지 않습니다.

protocol SomeProtocol { 
    func setValue(value: Int) 
} 

class ProtocolLabel : UILabel, SomeProtocol { 
    func setValue(value: Int) { 

    } 
} 

class ProtocolImageView : UIImageView, SomeProtocol { 
    func setValue(value: Int) { 
    } 
} 

viewForValue (2) 는 지금은 다음 함수를 정의했다. T가 프로토콜 SomeProtocol을 준수하는 UIView가 될 것으로 기대합니다. 내가 코드를 실행할 때

func viewForValue<T where T: SomeProtocol, T: UIView>(param: Int) -> UIView { 
    var someView: T 
    if param > 0 { 
     someView = ProtocolLabel() as T 
    } else { 
     someView = ProtocolImageView() as T 
    } 
    someView.setValue(2) 
    someView.frame = CGRectZero 
    return someView 
} 

그러나, 나는 다음과 같은 컴파일 오류를 받고 있어요 :

viewForValue(2) // <-- Type 'UIView' does not conform to protocol 'SomeProtocol' 

이 WHERE 절에 내가 프로토콜을 구현하지 않는 클래스를 지정할 수 없습니다 것 같다 . 왜 그런가요?

미리 감사드립니다.

+1

는이를 사용하려고 할 수 세그먼트 오류로 실패 : Greg

답변

4

viewForValueUIView에서 상속 받고 SomeProtocol을 구현하는 클래스를 반환한다고 가정합니다. 직접적인 관계가없는 클래스를 두 개 정의했습니다. 이들은 단지 UIView에서 상속 받고 SomeProtocol을 구현합니다.

함수가 반환 형식을 결정해야하는 경우 두 클래스가 상속하는 직접 구체 유형은 UIView이므로 viewForValue이 반환합니다.

protocol SomeProtocol { 
    func setValue(value: Int) 
} 

class SomeClass: UIView, SomeProtocol { 
    func setValue(value: Int) { 

    } 
} 

class SomeSubclass : SomeClass { 
} 

class SomeOtherSubclass : SomeClass { 
} 

func viewForValue<T where T: SomeProtocol, T: SomeClass>(param: Int) -> T { 
    var someView: T 
    if param > 0 { 
     someView = SomeSubclass() as T 
    } else { 
     someView = SomeOtherSubclass() as T 
    } 
    someView.setValue(2) 
    someView.frame = CGRectZero 
    return someView 
} 

viewForValue(2) 

부록을 : 문제를 해결하기 위해

, 당신은 UIView에서 상속 제 3 클래스를 생성하고 SomeProtocol 구현하여, 2 개 개의 클래스 사이의 직접적이고 구체적인 관계를 만들 수있는 읽기 OP 주석 아래에, 목적은 UIView에서 상속하는 기존 UIKit 클래스를 동적으로 인스턴스화하는 것입니다. 따라서 제안 된 해결책은 적용되지 않습니다.

protocol SomeProtocol { 
    func setValue(value: Int) 
} 

extension UIView : SomeProtocol { 
    func setValue(value: Int) { 
    } 
} 

func viewForValue<T where T: SomeProtocol, T: UIView>(param: Int) -> UIView { 
    var someView: T 
    if param > 0 { 
     someView = UILabel() as T 
    } else { 
     someView = UIImageView() as T 
    } 
    someView.setValue(2) 
    someView.frame = CGRectZero 
    return someView 
} 

을하지만, 컴파일러의 버그가있을 것 같습니다 :

나는 SomeProtocol해야 작업을 구현하여 UIView을 확장한다고 생각합니다. 놀이터에서이 코드는 다음과 같은 메시지를 보여줍니다 :

놀이터 서비스와의 통신이 예기치 않게 중단되었습니다. 놀이터 서비스 "com.apple.dt.Xcode.Playground"가 충돌 로그를 생성했을 수 있습니다. 아이폰 OS 응용 프로그램 컴파일에 반면

인해 11

+0

내 질문 더 일반적인려고 노력했지만 내 경우에 관련된 클래스는'UIView' 하위 클래스 인'UILabel','UIImageView'이므로 관련 클래스를 상속받을 수는 없습니다. 이를 반영하여 편집 할 것입니다. – Kamchatka

+0

내 대답에 추가 참조 - 제 2 솔루션을 작동해야한다고 생각하지만 코드를 컴파일러 충돌이 ... – Antonio

+0

이것은 도움이 감사합니다! – Kamchatka

관련 문제