2016-03-08 116 views
8

在該代碼時,該文本的變化,titleEditingChanged被調用(如預期)。但是,當它執行線爲什麼'didset'在設置屬性屬性時會調用屬性?

investment?.title = sender.text! 

它調用的Investmentdidset{}。 爲什麼?

class InvestmentCell: UITableViewCell { 

    var investment: Investment? { 
     didSet { 
      // setup UI elements from class properties 
      textField.text = investment?.title 
      valueField.text = investment?.value?.description 
     } 
    } 

    @IBAction func titleEditingChanged(sender: UITextField) { 
     investment?.title = sender.text! 
    } 

    @IBOutlet weak var textField: UITextField! 
    @IBOutlet weak var valueField: UITextField! 
} 
+0

「投資」是類還是結構? – EmilioPelaez

+0

這是正常行爲。當你將一個項目追加到一個數組時,也會發生同樣的情況。 –

+2

'didSet'和'willSet'是屬性觀察者*。你可以在[Swift Book](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html)中準備好他們。 –

回答

7

這就是所謂的,因爲Investment可能是一個結構,而不是一類。 在Swift中,結構是值類型,而不是類的引用類型。 所以,結構不是「可變的」。

這意味着,只要你改變一個結構屬性的新結構對象被分配給替換當前,當前對象的數據被複制到除了更改的屬性將包含新值,設置新的。

請記住,只要使用let命令(使用可執行的類)初始化struct對象,編譯器不會讓您更改struct屬性。

這就是爲什麼每當你改變一個結構屬性觀察者被調用。一旦一個新的結構對象被分配來替換當前的結構對象,它現在將被存儲在另一個內存塊中,所以它的值將被改變並且將被調用。

PS:如果您將Investment定義爲類而不是結構,則不會發生這種情況。

+1

我按照你的建議做了,並把struct Investment改爲class Investment,它有着理想的效果。 – ziggyzoggy

+2

另外請注意,像String,Array,Dictionary和Set這樣的標準類型都是值類型。因此擁有這些類型的屬性也會使didSet觀察者在屬性上調用任何訪問權限。 (這給了我很多頭痛) – codingFriend1

12

值類型(例如結構)的屬性觀察員也被稱爲當類型實例的下層屬性設置;因爲實例本身的值更新爲。同樣的不適用於參考類型;只要引用本身沒有變異,屬性觀察者就不會被調用(即引用本身可以被認爲是引用類型的值)。

Language Guide - Properties - Property Observers我們讀到:

地產觀察者觀察和對財產的價值 變化做出反應。地產觀察家稱爲每一個屬性的值是 設定的時間,即使新的值相同屬性的當前值


爲了驗證上述,考慮下面的例子:

/* reference type */ 
class InvestmentC { 
    var title: String = "Foo" 
} 

/* value type */ 
struct InvestmentS { 
    var title: String = "bar" 
} 

class InvestmentContainer { 
    var investmentC : InvestmentC { 
     didSet { 
      print("did set a property of 'InvestmentC' instance (ref. type)") 
     } 
    } 

    var investmentS : InvestmentS { 
     didSet { 
      print("did set a property of 'InvestmentS' instance (val. type)") 
     } 
    } 

    init() { 
     investmentC = InvestmentC() 
     investmentS = InvestmentS() 
    } 
} 

/* Example: property observer called only when setting a property 
      of the value type instance 'investmentC'    */ 
let foo = InvestmentContainer() 
foo.investmentC.title = "foobar" // prints: nothing 
foo.investmentS.title = "foobar" // prints: "did set a property of 'InvestmentS' instance (val. type)" 

因此,我們可以推斷出你的自定義類型Investment是值類型(結構),和實例的didSet財產觀察員即使您只設置/更新investment的基礎屬性,此類型的0(在您的UITableViewCell子類中)也會被調用。如果你想避免這種情況,改變Investment爲引用類型(類),在這種情況下,如果investment實例本身設置/更新didSet財產觀察者纔會發生改變。

+0

這是一個很好的答案,但最終我選擇了給Jorg B Jorge打勾,因爲我發現它更加簡潔和快速地理解問題。但你的回答更全面,也幫助我理解和解決問題。投資是一個結構,我確實把它改成了一個類,我找到了更透明的方式來編碼它。謝謝。 – ziggyzoggy