通过只读属性的Swift协议可设置属性
问题描述:
有人可以告诉我为什么Swift必须调用一个属性的setter,当它仅用于访问一个对象(协议)以设置其属性之一时?第一个例子说明,如果我不申报的间接对象设定我的错误:如果我给它一个二传手通过只读属性的Swift协议可设置属性
protocol AProtocol {
var name: String { get set }
}
class AnImplementation: AProtocol {
var name = ""
}
class AParent {
var test = AnImplementation()
}
class AChild {
var parent: AParent!
var test: AProtocol {
get { return parent.test }
// Note: Not settable
}
}
var parent = AParent()
var child = AChild()
child.parent = parent
child.test.name = "Hello world!" // Error: Cannot assign to property : 'test' is a get-only property
print(child.test.name)
,它编译和作品,但它调用setter方法:
protocol AProtocol {
var name: String { get set }
}
class AnImplementation: AProtocol {
var name = ""
}
class AParent {
var test = AnImplementation()
}
class AChild {
var parent: AParent!
var test: AProtocol {
get { return parent.test }
set(newTest) { print("Shouldn't be here!") }
}
}
var parent = AParent()
var child = AChild()
child.parent = parent
child.test.name = "Hello world!"
print(child.test.name)
输出:
Shouldn't be here!
Hello world!
我不知道我不理解这里。我想我可以给它一个空的二传手,但我想了解它的原因。
任何信息非常感谢!
答
您的协议声明改成这样:
protocol AProtocol:class {
var name: String { get set }
}
否则,它采取的是默认为值类型。更改值类型的属性会替换值类型实例(如setter观察者所示)。如果参考文献是let
参考文献,则不能这样做。
答
这可能是由于编译器不知道AChild.test
是类还是值类型。有了类,就没有问题,但赋值为name
的值类型也会创建一个赋值为test
(值复制行为)。将APProtocol
标记为class
协议将解决此问题。
扩大,当编译器不能确定test
是值或类型,它将使用的child.test.name = "Hello world!"
以下改写:
var tmp = child.test
tmp.test = "Hello world!"
child.test = tmp
,因为这将两个类和值类型的工作。
关于值类型setters,请参阅我的答案在这里例如:http://*.com/a/33901138/341994 – matt