我试图用一些AnyObject类型的属性来定义一个协议,然后在符合协议的类中,属性类型是SomeClass。但是这会返回编译器错误。我不得不将类中的类型更改为AnyObject。如何在协议定义中使用超类并将子类用作属性类型?
谢谢!
protocol TestProtocol {
var prop: [AnyObject] {get}
}
class Test: TestProtocol {
var prop = [SomeClass]() //compiler error
var prop = [AnyObject]() //this will work
}
答案 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]()
}