类型不符合协议

7

我仍然有些困难理解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
你可以尝试使用这个: <T where T: SomeProtocol, UIView> - Greg
1个回答

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)

补充说明: 根据下面OP的评论,目的是动态实例化继承自UIView的现有UIKit类。 因此,所提出的解决方案不适用。

我认为通过实现SomeProtocol来扩展UIView 应该可行:

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
}

但看起来似乎存在编译器错误。在一个游乐场中,这段代码会显示一个消息,说明:

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

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


我试图用更通用的方式提出我的问题,但在我的情况下,涉及的类是现有的 UIView 子类:UILabelUIImageView,因此我无法让它们继承自 SomeClass。我将进行编辑以反映这一点。 - Kamchatka
请看我回答的补充部分 - 我认为第二个解决方案应该可行,但是代码会导致编译器崩溃... - Antonio
它确实可以编译,但也会崩溃。但至少它是有意义的。 - Kamchatka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接