簡體   English   中英

為什么不能在其willSet事件中從數組中刪除元素?

[英]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塊中觀察的任何屬性突變willSetnewValue的實際存儲之前發生,而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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM