在 Swift 数组上使用 didSet 和 private(set)

Posted

技术标签:

【中文标题】在 Swift 数组上使用 didSet 和 private(set)【英文标题】:Using didSet and private(set) on Swift Array 【发布时间】:2015-09-20 06:38:38 【问题描述】:

我正在做一个快速的项目,我有几个数组。在我的一个数组中,我不希望客户端能够在不使用我特别定义的方法之一的情况下对其进行变异。另一方面,我希望 getter 可以访问。我的问题是关于附加和设置属性。

问题 1private(set) 是否会阻止客户呼叫 array.append

在另一个数组上,我想看看它是否已更改。

问题 2:如果我使用 didSet 将属性观察器添加到数组中,那么在将元素附加到数组时会调用 didSet 吗?

【问题讨论】:

【参考方案1】:

问题 1: private(set) 是否会阻止客户端调用 array.append?

是的。

问题 2:如果我使用 didSet 将属性观察器添加到数组中,那么在将元素附加到数组时会调用它吗?

是的,didSet 在调用 append() 时被调用。

【讨论】:

你知道这是否记录在任何地方吗? @onmyway133 我没有问答案是否已经过测试。我知道我可以自己测试它。我在问文档是否在任何地方提到了答案。如果正式提及,添加指向该文档的链接可能对希望了解更多详细信息的未来读者有所帮助。【参考方案2】:

当您意识到 Swift 中的数组有效地按值传递时,您的问题的答案就很容易理解了。我说得很有道理,因为它们表现就好像它们在通过时被复制了一样,但是在幕后有一些聪明的魔法来优化事物并避免实际上不必要地复制元素。

didSet 处理程序在属性值更改时调用,在 Swift 中包括数组。所以append() Swift 中的数组实际上类似于对整数的+=:首先读取数组,然后使用附加值创建一个新数组,然后将新数组写回属性.所以你可以看到,如果你在数组属性上调用append(),它肯定会调用didSet,同样,通过将set设为私有,外部用户将无法调用append(),因为他们不会能够将新值写回数组。

【讨论】:

所以理论上 if 数组是引用类型...附加到它不会导致didSet 回调? @Honey 没错。对可变引用类型的修改是在对象“内部”进行的,不会影响引用。另一方面,由于值类型是不可变的(更改任何内容都会创建一个全新的结构),因此正在更改的是整个值。 这在今天的 Swift 中仍然成立吗?我似乎无法在 Xcode 11.4.1,即 Swift 5.2 中重现这一点。 @TonyTopper 是的,它仍然是正确的,并且对于 Swift 的工作方式非常基础。【参考方案3】:
    问题 1 是的,因为变异函数调用会改变存储的值,因此 private(set) 确实禁止调用变异函数。 问题 2 是的,出于同样的原因,会触发观察者。

这里没有特定于数组的内容,这是由于数组是结构而append 是变异成员。调用append 与影响属性的新值非常相似。这不是很明确,但文档中有更多关于 mutating members 和 stored properties 的信息,这些信息支持了语言正确处理变异这一事实。

【讨论】:

以上是关于在 Swift 数组上使用 didSet 和 private(set)的主要内容,如果未能解决你的问题,请参考以下文章

Swift 中 willSet 和 didSet 的作用是啥?

Swift 中的 Getter 和 Setter - 改用 WillSet 和 DidSet 有意义吗?

已发布值上的 SwiftUI toggle() 函数停止使用 Swift 5.2 触发 didSet

DidSet在init函数swift 3中不起作用

Swift didSet for var 使用 @Binding 在子级中更改

具有默认值的 Swift public var 并为该默认值运行 didSet [重复]