【问题标题】:Type does not conform to protocol类型不符合协议
【发布时间】:2014-09-15 10:55:30
【问题描述】:

我仍然无法理解 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 子句中我无法指定不实现协议的类。这是为什么呢?

提前致谢。

【问题讨论】:

  • 你可以试试这个:

标签: ios generics swift protocols


【解决方案1】:

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

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

为了解决这个问题,你必须在 2 个类之间创建一个直接和具体的关系,方法是创建一个继承自 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
}

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

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

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

【讨论】:

  • 我试图对我的问题更通用,但在我的情况下,所涉及的类是现有的 UIView 子类:UILabelUIImageView 所以我不能让它们继承自 @ 987654338@。我将进行编辑以反映这一点。
  • 查看我的答案 - 我认为第二种解决方案应该可以工作,但代码会使编译器崩溃......
  • 它会编译但也会崩溃。但至少它是有道理的。
猜你喜欢
  • 2019-11-23
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-22
  • 2017-02-09
相关资源
最近更新 更多