我的类可以覆盖Swift中的协议属性类型吗?

时间:2015-08-01 20:14:54

标签: swift protocols

protocol Parent {
     var children: [AnyObject] { get set }
}

class Foo {
}

class Bar: Parent { //error happens here
    var children = [Foo]()

    init() {}
}

我收到错误“类型'对象'不符合协议'父'。我得到这个错误的原因是因为我将子节点定义为Foo而不是AnyObject的数组。我有什么方法可以做到这一点工作?

5 个答案:

答案 0 :(得分:9)

在协议中要求AnyObject意味着children数组必须能够接受AnyObject个条目。但听起来你希望Bar的孩子只是Foo个对象。

相反,您可以为协议指定associated type

protocol Parent {
    associatedtype Child
    var children: [Child] { get set }
}

class Foo { }

class Bar: Parent {
    var children = [Foo]()
    init() {}
}

答案 1 :(得分:2)

如果你总是想要一个AnyObject类型的数组,你必须在你的类中指定它:

class Bar: Parent {
    var children = [AnyObject]()
    init() {}
}

但如果您可以使用更具体的typealias协议,您可以像这样重写协议:

protocol Parent {
     // in Swift 1 and 2: use `typealias` instead of `associatedtype`
     associatedtype T: AnyObject // this makes sure that all instances in the array are definitely of type `AnyObject` / classes
     var children: [T] { get set }
}

这样你以前对你的类的一致性有效,但是你必须考虑这个协议只能用作泛型约束,因此只能用在函数和泛型声明中:

// --- this does work
func someFunc<T: Parent, U: Parent>(p1: T, p2: U) { /* ... */ }

class SomeClass<T: Parent> { /* ... */ }


// --- this doesn't work
let parent: Parent
let array: [Parent]
// here you can only use types which conform to the protocol
// but not the protocol itself as generic arguments
let something = SomeClass<Parent>()

答案 2 :(得分:1)

如果协议声明存在[AnyObject]类型的getter和setter,则意味着必须有这样的getter和setter,而不是该类的子类型。

你的代码在逻辑上是错误的 - 因为你可以设置,例如某些[Int](协议说它可能)到[Foo]类型的变量(类只有这个变量)< / p>

所以这实际上是唯一正确的方法。

protocol Parent {
    var children: [AnyObject] { get set }
}

class Foo {
}

class Bar: Parent { //error happens here
    var children = [AnyObject]()

    init() {}
}

在swift 2.0中,typealias可能是另一种选择。

答案 3 :(得分:0)

不,你不能改变一个属性的类型。

将此添加到您的栏类:

var childrenObject: Foo {
    get {
        return self.children as! Foo
    }
}

答案 4 :(得分:0)

协议答案的替代方案可能会给您一些协议所带来的好处。

class Parent<T : RawRepresentable> where T.RawValue == Int {
    var value : T

    init(withValue v : T) {
        self.value = v
    }
}

enum testOne : Int {
    case one
    case two
}

enum testTwo : Int {
    case three
    case four
}

class ChildOne : Parent<testOne> {}

class ChildTwo : Parent<testTwo> {}

let c1 = ChildOne(withValue: testOne.one)
print(c1.value)
let c2 = ChildTwo(withValue: testTwo.three)
print(c2.value)

相关:How in Swift specify type constraint to be enum?