类型不符合协议

Kam*_*tka 7 generics protocols ios swift

我仍然无法理解Swift中泛型的一些微妙之处.我定义了以下类型:

protocol SomeProtocol {
    func setValue(value: Int)
}

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

    }
}

class ProtocolImageView : UIImageView, SomeProtocol {
    func setValue(value: Int) {
    }
}
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

但是,当我执行代码时,我收到以下编译错误:

viewForValue(2) // <-- Type 'UIView' does not conform to protocol 'SomeProtocol'
Run Code Online (Sandbox Code Playgroud)

似乎在where子句中我不能指定不实现协议的类.这是为什么?

提前致谢.

Ant*_*nio 4

viewForValue应该返回一个继承UIView并实现的类SomeProtocol。您定义了两个没有直接关系的类 - 它们只是继承UIView并实现SomeProtocol

当函数必须确定返回类型时,两个类继承的直接具体类型都是UIView,所以这就是viewForValue返回的内容。

为了解决这个问题,您必须通过创建继承UIView并实现的第三个类,在两个类之间创建直接且具体的关系SomeProtocol

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)
Run Code Online (Sandbox Code Playgroud)

附录:阅读下面的OP注释,目的是动态实例化继承自的现有UIKit类UIView. 因此建议的解决方案不适用。

我认为UIView通过实施来扩展SomeProtocol 应该有效:

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
}
Run Code Online (Sandbox Code Playgroud)

但看起来有一个编译器错误。游乐场中的这段代码显示一条消息,指出:

与游乐场服务的通信意外中断。Playground 服务“com.apple.dt.Xcode.Playground”可能已生成崩溃日志。

而在 iOS 应用程序中,编译由于分段错误而失败 11。