Swift协议符合:候选者具有不匹配类型

时间:2016-01-22 01:30:30

标签: ios swift

我试图用一些AnyObject类型的属性来定义一个协议,然后在符合协议的类中,属性类型是SomeClass。但是这会返回编译器错误。我不得不将类中的类型更改为AnyObject。如何在协议定义中使用超类并将子类用作属性类型?

谢谢!

protocol TestProtocol {
    var prop: [AnyObject] {get}
}

class Test: TestProtocol {
    var prop = [SomeClass]()    //compiler error
    var prop = [AnyObject]()   //this will work
}

4 个答案:

答案 0 :(得分:10)

数组是一个不必要的复杂功能,所以让我们删除它,只考虑一个简单的类型。这不合法:

protocol TestProtocol {
    var prop: AnyObject {get}
}

class SomeClass {}

class Test: TestProtocol {
    var prop : SomeClass = SomeClass() // error
}

问题在于,协议声明确实声称声称采用TestProtocol的人必须具有AnyObject 类型的属性prop - 不是仅仅符合<的某种类型的属性/ em>到AnyObject。

如果您发现这一点令人惊讶,您可能会将类型实例与类型本身混淆。确实可以在需要AnyObject的实例的地方使用SomeClass的实例。但是类型本身不能这样工作;当协议要求类型 AnyObject时,您无法替换类型 SomeClass。

要更清楚地看到这一点,请注意此 编译得很好:

protocol TestProtocol {
    var prop: AnyObject {get}
}

class SomeClass {}

class Test: TestProtocol {
    var prop : AnyObject = SomeClass() // changing the declared _type_
}

正如你已经发现的那样编译;但是,正如你所说,这不是你想要的。那么如何做你想做的事呢?

好吧,在Swift中,表达指定符合协议类型类型的概念的方式是通过带有约束的泛型。这就是你得到的答案。协议声明中的typealias可以是制定通用协议的一种方式。并且通用可以具有约束,例如,有问题的类型应符合协议或从类继承。因此,这是合法的,是您正在寻找的解决方案:

protocol TestProtocol {
    typealias T:AnyObject // generic
    var prop: T {get}
}

class SomeClass {}

class Test: TestProtocol {
    var prop : SomeClass = SomeClass() // :)
}

typealias T:AnyObject表示T必须是符合AnyObject 类型,正好您要说的内容。

答案 1 :(得分:5)

你可以做的一个游乐场示例:

class SomeClass {

}

class Subclass : SomeClass{

}

protocol TestProtocol {
  typealias T : SomeClass
  var prop: [T] {get}
}

class Test: TestProtocol {
  var prop = [Subclass]()

  func test(){
    prop.append(Subclass())
  }
}

let test = Test()
test.test() 
print(test.prop) // prints "[Subclass]\n"

答案 2 :(得分:1)

您可以通过使用类型别名要求来避免将数组元素类的知识推向协议:

protocol TestProtocol 
{
    typealias ArrayElement: AnyObject
    var prop: [ArrayElement] {get}
}

class Test: TestProtocol 
{
    typealias ArrayElement  = SomeClass
    var prop:[ArrayElement] = []    //No compiler error
}

答案 3 :(得分:0)

这是在Swift 5中使用associatedtype的方式:

protocol TestProtocol {
    associatedtype T: AnyObject
    var prop: [T] {get}
}

class SomeClass {}

class Test: TestProtocol {
    var prop = [SomeClass]()
}

请注意,仅当您的SomeClass是具体类型时,此方法才有效。如果有协议类型,则无法使用。例如:

protocol TestProtocol {
    associatedtype T: AnyObject
    var prop: [T] {get}
}

protocol SomeProtocol: AnyObject {}

class Test: TestProtocol {
    var prop = [SomeProtocol]()
}