首页 > 解决方案 > 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

我显然不想要这个。有人知道如何解决这个问题吗?

标签: swift

解决方案


发生了什么

你只做了一个实例。然后,您创建了一个数组,其中包含对该单个实例的 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参数的任何内容都会被复制。

对于类,“复制”需要对完全相同的堆分配对象进行新引用。它通常也保留在过程中(将其引用计数增加一),但这在这里并不重要。因此,当您调用 时Array(repeating: ShoeInfo(), count: 80),只创建了一个ShoeInfo实例,然后代码将其复制了 80 次,这意味着它对同一个实例进行了 80 次复制引用。

对于结构,“复制”意味着完全复制它们,成员明智的。当您尝试 时Array(repeating: ShoeInfoAsAStruct(), count: 80),您将创建一个ShoeInfoAsAStruct(),然后将其复制到阵列的 80 个插槽中的每一个中,从而产生 80 个完整副本。您最终会得到 80 个不同的副本,每个副本都可以单独编辑。这就是为什么切换到struct工作。


推荐阅读