[英]Why can't I remove elements from an Array in its willSet event?
邏輯是在數組具有指定數量的元素時清除它。 我可以將檢查放在Array之外,但是我試圖在Array的willSet事件中查看該怎么辦。 結果是數組中的元素保持靜止。
這是代碼
var MyArr=[String]() {
willSet{
print("now count is:\(MyArr.count)")
if MyArr.count>2 {
print("now remove all!")
MyArr.removeAll()
}
}
}
MyArr.append("hello")
MyArr.append(",world")
MyArr.append("!")
MyArr.append("too much.")
print("The conent is \(MyArr)")
預期MyArr僅包含一個元素,而實際結果為四個。
該行為與值類型/引用類型無關
請注意警告
嘗試將屬性“ MyArr”存儲在其自己的willSet中,該屬性將被新值覆蓋
這意味着在willSet
中修改對象無效。
引用語言指南-屬性-屬性觀察者 [ 重點 ]:
物業觀察員
財產觀察員觀察並響應財產價值的變化。
...
您可以選擇在屬性上定義這些觀察者之一或全部:
- 將在存儲值之前調用
willSet
。- 存儲新值后,將立即調用
didSet
。
當您使用willSet
屬性觀察器進行實驗時,在willSet
塊中觀察的任何屬性突變willSet
在newValue
的實際存儲之前發生,而newValue
的實際存儲緊隨willSet
塊之后。 這意味着您實際上是在嘗試將myArr
“舊副本”突變為新值之前。
可以說,這可能是一些非法的討論,作為任何突變myArr
按理說應該導致任何財產觀察員的調用,因此性能觀察者(引用類型的引用或值類型的值的突變)內的財產的突變可能導致對屬性觀察者的遞歸調用。 但是,情況並非如此,對於willSet
情況,尤其是,發出警告,如@vadian的答案中指出的那樣。 在屬性觀察器中對屬性本身進行更改不會觸發屬性觀察器的事實並沒有得到很好的記錄,但是《語言指南-屬性-類型屬性》中的示例指出了這一點[ 強調我的]:
查詢和設置類型屬性
...
currentLevel
屬性具有didSet
屬性觀察器,currentLevel
在設置currentLevel
時檢查其值。 ...注意
在這兩個檢查的第一個中,
didSet
觀察器將currentLevel
設置為不同的值。 但是,這不會導致再次調用觀察者。
這也是我們可以預料到的一種特殊情況,例如didSet
是合並例如將給定屬性值限制在某些范圍內的范圍檢查的絕佳場所。 也就是說,如果前者超出范圍,則用有界值覆蓋新值。
現在,如果在存儲新值之后更改為將屬性突變為,則該突變將生效,並且如上所述,不會觸發對屬性觀察器的任何其他調用。 應用於您的示例:
var myArr = [String]() {
didSet {
print("now count is: \(myArr.count)")
if myArr.count > 2 {
print("now remove all!")
myArr.removeAll()
}
}
}
myArr.append("hello")
myArr.append(",world")
myArr.append("!")
myArr.append("too much.")
print("The content is \(myArr)") // The content is ["too much."]
aAlan對評論didSet
VS willSet
很有趣。 我嘗試了相同的代碼,但是使用didSet
,它確實從數組中刪除了看起來很奇怪的元素。 我認為這是設計使然。 我的理由是:
willSet
確實獲得了對實際項目的引用並進行了更改,則所有內容都將被覆蓋。 它使所有更改無效。 因為您甚至在閱讀即將發生的事情之前就已經在這樣做。 另外(重復dfri所說的內容),如果再次在willSet
設置它,那么將一次又一次觸發屬性觀察器,並創建一個反饋循環,這將使編譯器崩潰,因此,幕后的編譯器將didSet
並非如此。 您等待...讀取值,然后做出決定。 您知道該屬性的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.