Swift计算属性出现重复值问题:为何得到[3,3,2]而非预期[3,2]?
为什么Swift计算属性调用append会导致重复值?
我来帮你拆解这个问题的核心原因——你误解了计算属性和值类型(比如Swift的Array)交互时的行为,尤其是调用mutating方法(比如append)时的隐式赋值逻辑。
一步一步还原你的代码执行流程
初始化阶段(init方法)
- 你先把
_x初始化为空数组[]。 - 执行
x?.append(3):- 首先调用计算属性
x的getter,返回当前_x的值(空数组)。 - 对这个返回的数组调用
append(3),因为数组是值类型,这会创建一个新的数组实例[3]。 - 关键来了:因为你是对计算属性的返回值进行修改,Swift会自动把这个修改后的新数组重新赋值给计算属性
x,也就是触发了x的setter方法。 - 在setter里,
newValue就是刚才的[3],你遍历它的元素并追加到_x中(此时_x还是空数组),所以_x变成了[3]。
- 首先调用计算属性
追加2的阶段
- 执行
classTest.x?.append(2):- 调用
x的getter,返回当前_x的值[3]。 - 对这个数组调用
append(2),再次创建新的数组实例[3,2]。 - Swift再次自动把这个新数组赋值给
x,触发setter。 - 在setter里,
newValue是[3,2],你把这两个元素都追加到现有的_x([3])里,最终_x就变成了[3,3,2]。
- 调用
为什么和你的预期不符?
你以为调用x?.append(3)是直接修改_x,但实际上因为x是计算属性(而非存储属性),对它的返回值调用mutating方法会触发隐式赋值,进而触发你写的setter逻辑——而你的setter是把newValue的元素追加到_x,不是替换,这就导致了重复。
怎么修复?
如果你想让x的行为和普通的存储属性一样,直接操作_x,有两个选择:
- 把
x改成存储属性,去掉getter和setter(或者干脆不用下划线命名,直接用x作为存储属性):
class Test { var x: [Int] = [] init() { x.append(3) } }
- 如果你必须保留计算属性,修改setter的逻辑为替换而非追加:
class Test { var _x : [Int]? var x : [Int]? { get { return _x } set { _x = newValue } // 直接替换,不是追加 } init() { _x = [Int]() _x?.append(3) // 直接操作存储属性,避免不必要的getter/setter调用 } }
内容的提问来源于stack exchange,提问作者dev_ios999
相关产品推荐
相关产品推荐

