3

逻辑是在数组具有指定数量的元素时清除它。我可以将检查放在 Array 之外,但我试图在 Array 的 willSet 事件中查看是否执行此操作。结果是 Array 中的元素保持静止。

这是代码

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 预计只有一个元素,而实际结果是四个。

4

3 回答 3

3

该行为与值类型/引用类型无关

请注意警告

试图在其自己的 willSet 中存储到属性“MyArr”,该 willSet 即将被新值覆盖

这意味着修改对象willSet没有效果。

于 2018-07-23T15:27:45.560 回答
2

引用语言指南 - 属性 - 属性观察者[强调我的]:

物业观察员

属性观察者观察并响应属性值的变化。

...

您可以选择在属性上定义其中一个或两个观察者:

  • willSet在存储值之前调用。
  • didSet在存储新值后立即调用。

当您正在使用willSet属性观察器进行试验时,您在willSet块内观察到的属性的任何突变都在实际存储之前newValue,紧跟在willSet块之后。这意味着您实际上是在尝试在将“旧副本”myArr替换为其新值之前对其进行变异。

可以说这可以被讨论为非法的,因为任何突变都myArr应该导致任何属性观察者的调用,因此属性观察者中的属性突变(引用类型的引用或值类型的值的突变)可能会导致递归调用属性观察者。然而,情况并非如此,对于这种willSet情况,特别是会发出警告,正如@vadian 的回答中所指出的那样。在属性观察者中属性本身的突变不会触发属性观察者这一事实并没有得到很好的记录,但是语言指南 - 属性 - 类型属性中的一个示例指出了这一点[强调矿]:

查询和设置类型属性

...

currentLevel属性有一个didSet属性观察器来检查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."]
于 2018-07-23T21:46:01.377 回答
1

aAlan 对didSetvs的评论willSet很有趣。我尝试了相同的代码,但didSet确实从数组中删除了最初看起来很奇怪的元素。我认为这是设计使然。我的理由是:

  • 如果您确实获得了对内部实际项目本身的引用willSet并进行了更改,那么一切都会被覆盖。它使您的所有更改都无效。因为您甚至在阅读将要发生的事情之前就已经这样做了。另外(重复 dfri 所说的)如果你在里面再次设置它,那么你将一次又一次willSet地触发属性观察器,并将创建一个反馈循环,这将使编译器崩溃,因此场景后面的编译器创建一个副本,避免这一切......只会抑制这种突变,即它不会允许它。它不会创建副本......简单地说它会忽略它。它通过抛出一个模糊的警告来做到这一点(因为它并没有真正告诉你它会忽略这些变化)警告:

在此处输入图像描述

  • 情况并非如此didSet。您等待...读取值,然后做出决定。您知道财产的价值。
于 2018-07-23T15:30:11.387 回答