有一个数据源单例
class hugestuff ..{
var dataSources: [String: ThingWithIncrediblyLargeArrays] ..
var currentThing: String
}
ThingWithIncrediblyLargeArrays
确实是struct
。典型的用途可能是在屏幕上的网格中显示巨大的值表。每个 ThingWithIncrediblyLargeArrays
- 也就是说 .dataSources
字典中的每个条目 - 可能是不同的屏幕。
struct ThingWithIncrediblyLargeArrays {
var rawUnsorted: [[String]]
var liveSorted: [[String]]
var swapValues: [[String]]
}
因此,在整个应用程序中,您都在访问
cell.data = hugestuff.dataSources[currentThing].unsortedRows[3489412]
等等。
确实有时会改变事情......
hugestuff.dataSources[currentThing].searchRows =
hugestuff.dataSources[currentThing].unsortedRows.filter{blah}
这一切都太棒了,但是纯粹是糖如果
会更方便、更坚固 cell.data = hugestuff.hot.unsortedRows[3489412]
hugestuff.hot.searchRows = hugestuff.hot.unsortedRows.filter{blah}
现在,我相信要实现这一目标,如果你这样做
var hot: ThingWithIncrediblyLargeArrays {
get { dataSources[currentThing] }
set { dataSources[currentThing] = newValue }
}
一切正常。
换句话说,在这种情况下,使用 Swift 中的字典来执行“类似指针或宏的事情”的方法如上所述。
事实上,这是否能按照预期的方式安全、正确地发挥作用?也就是说,
(一)
x = hugestuff.hot.enormousArray[13]
将不会在此过程中无意义地复制数组并且
(B)
hugestuff.hot.searchRows = .. some new or modified array
确实会“实际更改”该数组,即,它不会只是错误地更改数组某处的某些临时副本。
hugestuff.hot.searchRows = hugestuff.hot.other.sortwhatever
希望能和
一样hugestuff.dataSources["electrons"].searchRows =
hugestuff.dataSources["electrons"].other.sortwhatever
换句话说,我希望
hugestuff.hot.searchRows = ..
事实上真的会改变hugestuff.dataSources["electrons"]
这完全正确吗?
我提到“当前”Swift,当然是因为,Swift 在某一点上极大地改变了数组的工作方式,并且 Swift 使用了巧妙的 (“但是在尝试任何棘手的事情之前先询问一下”) 仅按需复制大数组(或实际上任何数组)的方法。
顺便说一句,这里是对相关问题的非常有用的答案Swift > 绝对不会吗< deep copy a large array, when one "guard let" the array?
如果
ThingWithIncrediblyLargeArrays
是一个类,则 hot
将简单地充当“指针”。毕竟,类是 reference 类型,并且 hot
将返回引用。
从现在开始我将假设
ThingWithIncrediblyLargeArrays
是一个结构体。
Array
是复制-写。对于要复制的数组存储,它必须
Array
变量共享(即 isKnownUniquelyReferenced
为 false)在 A 和 B 两种情况下,
hot
的 getter 返回 ThingWithIncrediblyLargeArrays
的副本,但副本中的数组将共享相同的存储,因为您没有写入 hugestuff.hot.enormousArray
。
但是,
hot
并不完全像指针。如果你这样做:
hugeStuff.hot.enormousArray[someIndex] = something
hot
返回ThingWithIncrediblyLargeArrays
的副本,它与dataSources[currentThing]
共享数组存储。然后您修改了 enormousArray
返回的副本的 hot
。现在数组存储无法共享,因此整个数组存储将被复制。
您可以将其视为:
let temp = hugeStuff.hot
temp.enormousArray[someIndex] = something
hugeStuff.hot = temp
此处并未唯一引用数组存储 -
temp
和 huge.dataSources[someIndex]
共享存储。
确定数组存储是否被复制的一个好方法是使用 Instruments 中的“Allocations”工具。使用以下代码尝试一下:
struct ThingWithIncrediblyLargeArrays {
var enormousArray = Array(repeating: 1, count: 1000)
var searchRows = ["Row1", "Row2", "Row3"]
}
class HugeStuff {
var dataSources = ["Foo": ThingWithIncrediblyLargeArrays()]
var currentThing = "Foo"
var hot: ThingWithIncrediblyLargeArrays {
@inlinable
get { dataSources[currentThing]! }
@inlinable
set { dataSources[currentThing] = newValue }
}
}
let hugeStuff = HugeStuff()
// run each of these loops separately:
// case A
//for i in 0..<1000 {
// let x = hugeStuff.hot.enormousArray[i]
// print(x)
//}
// case B
//for i in 0..<1000 {
// hugeStuff.hot.searchRows = ["Row \(i)"]
// print("x")
//}
// case C
//for i in 0..<1000 {
// hugeStuff.hot.enormousArray[i] = i
// print("x")
//}
您可以按“数组”进行过滤,您将在案例 C 的 Instruments 中看到类似的内容:
名称
_TtGCs23_ContiguousArrayStorageSi_
是 ContiguousArrayStorage<Int>
的变形名称。您可以使用 swift demangle
命令对它们进行分解。