2016-04-28 103 views
0

有人可以告诉我为什么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! 

我不知道我不理解这里。我想我可以给它一个空的二传手,但我想了解它的原因。

任何信息非常感谢!

回答

2

您的协议声明改成这样:

protocol AProtocol:class { 
    var name: String { get set } 
} 

否则,它采取的是默认为值类型。更改值类型的属性会替换值类型实例(如setter观察者所示)。如果参考文献是let参考文献,则不能这样做。

+0

关于值类型setters,请参阅我的答案在这里例如:http://stackoverflow.com/a/33901138/341994 – matt

2

这可能是由于编译器不知道AChild.test是类还是值类型。有了类,就没有问题,但赋值为name的值类型也会创建一个赋值为test(值复制行为)。将APProtocol标记为class协议将解决此问题。

扩大,当编译器不能确定test是值或类型,它将使用的child.test.name = "Hello world!"以下改写:

var tmp = child.test 
tmp.test = "Hello world!" 
child.test = tmp 

,因为这将两个类和值类型的工作。