Swift:尽管在for循环中进行了赋值,但所有类实例的布尔值都保持不变
我有以下数组:
var shoes = Array(repeating: ShoeInfo(), count: 80)
其中ShoeInfo定义如下:
class ShoeInfo {
var expressionOn: Bool?
var volumeControl: Bool?
var channel: Int?
}
我有一个for循环:
for i in 0..<16 {
if cond {
shoeArray[i].expressionOn = true
} else {
shoeArray[i].expressionOn = false
}
}
本质上,for循环中分配的最后一个值成为shoes数组中每个类实例的值!
我显然不想要这个。有谁知道如何解决这个问题?
回答
发生了什么
你只做了一个实例。然后,您创建了一个包含对该单个实例的 80 个引用的数组。自己看看,试试:
for shoe in shoes {
print(ObjectIdentifier(shoe))
}
你会看到所有的引用都指向一个单一的对象。
您可能正在寻找什么
这是:
let shoes = (0..<80).map { _ in ShoeInfo() }
该map调用将为 range 中的 80 个整数中的每一个调用一次闭包0..<80,这将导致实例化 80 个不同的鞋类对象。
有用的背景
Array(repeating:_count:_)按值获取其参数(注意没有inout)。因此,当您调用它时,您作为参数传递给repeating参数的任何内容都会被复制。
对于类,“复制”需要对完全相同的堆分配对象进行新的引用。它通常也保留在进程中(将其引用计数增加 1),但这在这里并不重要。因此,当您调用 时Array(repeating: ShoeInfo(), count: 80),只创建了一个ShoeInfo实例,然后代码将其复制了 80 次,这意味着它对同一个实例进行了 80 次复制引用。
对于结构,“复制”需要按成员方式完全复制它们。当您尝试 时Array(repeating: ShoeInfoAsAStruct(), count: 80),您将创建一个ShoeInfoAsAStruct(),然后将其复制到阵列的 80 个插槽中的每一个中,从而产生 80 个完整副本。您最终会得到 80 个不同的副本,每个副本都可以单独编辑。这就是为什么切换到struct工作。