简体   繁体   English

迅捷:无法为协议的属性分配值?

[英]Swift: Failed to assign value to a property of protocol?

Class A provides a string value. A类提供一个字符串值。 Class B has two members of A type inside itself, and provide a computed property "v" to choose one of them. 类B本身具有两个A类型的成员,并提供一个计算属性“ v”来选择其中之一。

class A {
    var value: String

    init(value: String) {
        self.value = value
    }
}

class B {
    var v1: A?
    var v2: A = A(value: "2")

    private var v: A {
        return v1 ?? v2
    }

    var value: String {
        get {
            return v.value
        }
        set {
            v.value = newValue
        }
    }
}

This code is simple and it works. 这段代码很简单,可以正常工作。 Since both the A and B have a member "value", I make it a protocol like this: 由于A和B都具有成员“值”,因此我将其设为这样的协议:

protocol ValueProvider {
    var value: String {get set}
}

class A: ValueProvider {
    var value: String

    init(value: String) {
        self.value = value
    }
}

class B: ValueProvider {
    var v1: ValueProvider?
    var v2: ValueProvider = A(value: "2")

    private var v: ValueProvider {
        return v1 ?? v2
    }

    var value: String {
        get {
            return v.value
        }
        set {
            v.value = newValue // Error: Cannot assign to the result of the expression
        }
    }
}

If I change the following code 如果我更改以下代码

v.value = newValue

to

var v = self.v
v.value = newValue

It works again! 它再次起作用!

Is this a bug of Swift, or something special for the property of protocols? 这是Swift的错误,还是协议属性的特殊之处?

You have to define the protocol as a class protocol: 您必须将协议定义为class协议:

protocol ValueProvider : class {
    var value: String {get set}
}

Then 然后

var value: String {
    get { return v.value }
    set { v.value = newValue }
}

compiles and works as expected (ie assigns the new value to the object referenced by v1 if v1 != nil , and to the object referenced by v2 otherwise). 编译和按预期工作(即分配新的值被引用的对象v1如果v1 != nil ,并通过引用的对象v2以其他方式)。

v is a read-only computed property of the type ValueProvider . vValueProvider类型的只读计算属性。 By defining the protocol as a class protocol the compiler knows that v is a reference type , and therefore its v.value property can be modified even if the reference itself is a constant. 通过将协议定义为类协议,编译器知道v引用类型 ,因此即使引用本身是常量,也可以修改其v.value属性。

Your initial code example works because there the v property has the type A which is a reference type. 您的初始代码示例有效,因为那里的v属性具有类型A ,这是引用类型。

And your workaround 和您的解决方法

set {
    var tmp = v1 ?? v2
    tmp.value = newValue
}

works because (read-write) properties of variables can be set in any case (value type or reference type). 之所以起作用,是因为可以在任何情况下(值类型或引用类型)设置变量的 (读写)属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM