A类提供一个字符串值。类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 } } }
这段代码很简单,可以正常工作。由于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 } } }
如果我更改以下代码
v.value = newValue
至
var v = self.v v.value = newValue
它再次起作用!
这是Swift的错误,还是协议属性的特殊之处?
您必须将协议定义为class协议:
class
protocol ValueProvider : class { var value: String {get set} }
然后
var value: String { get { return v.value } set { v.value = newValue } }
编译并按预期方式工作(即,将新值分配给v1if v1 != nil所引用的对象,v2否则分配给否则所引用的对象)。
v1
v1 != nil
v2
v是类型的只读计算属性ValueProvider。通过将协议定义为类协议,编译器知道这v是 引用类型 ,因此v.value 即使引用本身是常量,也可以修改其属性。
v
ValueProvider
v.value
您的初始代码示例有效,因为该 v属性具有A引用类型的类型。
A
和您的解决方法
set { var tmp = v1 ?? v2 tmp.value = newValue }
之所以起作用,是因为可以在任何情况下(值类型或引用类型)设置 变量的 (读写)属性。