2016-04-28 147 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 

,因爲這將兩個類和值類型的工作。