2015-10-05 34 views
2

我已經爲遵守協議的結構創建了一個全局變量。該變量有一個setter觀察者,每當設置變量時就完成一項任務。由於結構本身遵守協議,我希望變量的類型是協議類型。安裝程序在計算變量訪問計算變量期間調用struct,協議轉換

protocol TestProtocol { 
    var someInt: Int {get set} 
    var computedVar: Int {get} 
    func funcCall() -> Int 
} 

struct TestStruct: TestProtocol { 
    var someInt: Int = 1 

    var computedVar: Int { 
     return 0 
    } 

    func funcCall() -> Int { 
     return 2 
    } 
} 

var testProtocolVar: TestProtocol = TestStruct() { 
    willSet(newTest) { 
     print ("*** Setter testProtocolVar called!!!") 
    } 
} 

問題是,當我得到一個協議屬性的值是結構中的計算屬性時,變量設置器也被調用。

/*** 
    When a variable is defined and typecast as a protocol, calling a 
    computed variable on the variable (a class or a struct) the setter 
    method of the variable will be called (Undesired Behaviour). 
***/ 

print ("\n\n *** Test Protocol Cast Variable *** \n\n") 
testProtocolVar 
testProtocolVar.someInt 
print("Setter has not been called") 
testProtocolVar.funcCall() 
print("Setter has not been called after function") 
testProtocolVar.computedVar 
print("Setter has been called when using computed variable") 

/* 
    *** Test Protocol Cast Variable *** 


    Setter has not been called 
    Setter has not been called after function 
    *** Setter testProtocolVar called!!! 
    Setter has been called when using computed variable 
*/ 

變量是結構類型的類似情況不會觸發setter。

print ("\n\n *** Test Normal Cast Variable *** \n\n") 

/*** 
    When a variable is defined and typecast as the struct type, calling a 
    computed variable on the variable the setter method of the variable 
    will NOT be called (Desired Behaviour). 
***/ 

var testVar:TestStruct = testProtocolVar as! TestStruct 

testVar 
testVar.someInt 
print("Setter has not been called") 
testVar.funcCall() 
print("Setter has not been called after function") 
testVar.computedVar 
print("Setter has not been called when using computed variable") 

/* 
    *** Test Normal Cast Variable *** 


    Setter has not been called 
    Setter has not been called after function 
    Setter has not been called when using computed variable 
*/ 

有沒有人有解釋爲什麼設置觀察員被稱爲?

這似乎是一個迅速的錯誤,除非我失去了一些東西。

+1

我認爲這是一個錯誤。 – courteouselk

+0

同意。對我來說看起來像一個bug。 –

回答

0
protocol TestProtocol { 
     var someInt: Int {get set} 
     var computedVar: Int {get} 
     func funcCall() -> Int 
    } 

    struct TestStruct: TestProtocol { 
     var someInt: Int = 1 
     var computedVar: Int { 
      return 0 
     } 
     func funcCall() -> Int { 
      return 2 
     } 
    } 

    var testProtocolVar: TestProtocol = TestStruct() { 
     willSet { 
      print ("*** Setter testProtocolVar called!!!", newValue) 
     } 
    } 

    var i: CustomStringConvertible = Int(10) { 
     willSet { 
      print("*** Setter Int called!!!", newValue) 
     } 
    } 

    let a = testProtocolVar 
    let b = a.computedVar 
    let c = testProtocolVar.computedVar // *** Setter testProtocolVar called!!! TestStruct(someInt: 1)  
    let j = i 
    let k = j.description 
    let l = i.description // *** Setter Int called!!! 10 

你認爲這是一個錯誤?它似乎對我很好......

的willSet和didSet觀察者提供了一種方法來觀察(並適當 響應)當一個變量或屬性的值是 被設置。第一次初始化變量或屬性 時,不會調用觀察者。相反,只有在初始化上下文之外設置的值爲 時纔會調用它們。

+0

我不知道爲什麼你認爲這應該是默認行爲。調用computedVar計算機屬性應該簡單地返回0.它不應該導致testProtocolVar的設置。作爲一個例子,獲取someInt變量沒有這個結果。 – Brett

+0

我可以想象,計算出的屬性值是通過設置閉包進行計算的,並與「一般」存儲屬性的關閉一起報告。即使設置閉包在外部不可用,它仍應在收到之前設置該值。這符合上面的引文。據我瞭解,這是計算的屬性和函數之間的差異。willSet,set,didSet和get通常不在外部訪問,並且是屬性實現的一部分。我明白,我們的期望是不同的,但沒有人告訴我們,所以它不是一個錯誤 – user3441734

+0

順便說一句,在Xcode版本7.2測試版(7C46l)相同的代碼打印沒有:-) – user3441734

2

這似乎在Xcode 7.2的β2正式固定在Xcode 7.2的β2

解決的問題 - SWIFT 2.1和Objective-C夫特 編譯器在夫特的先前版本中,如果一個類型有一個可變的 屬性的協議類型,「鏈」訪問屬性的屬性總是被視爲屬性的突變,即使 第二個屬性只能被讀取,而不是寫入。例如:

protocol Countable { 
     var count: Int { get } 
    } 
    class MyObject { 
     var widgets : Countable { 
      didSet { print("in didSet") } 
} } 
    var obj : MyObject = ... 
    let count = obj.widgets.count 

這將執行一個假寫回屬性窗口小部件, 造成didSet意外火災。解決辦法是分割 接入到不同的表情,就像這樣:

let widgets = obj.widgets 
    let count = widgets.count 

此bug已得到修復。 (22953072)