我有一个包含一种对象的数组字典:数据库记录。 每个数组就像一个与字典中的键(表名)相关联的表。
我的问题是:如何更新表(删除记录,添加记录等)而不制作表的任何临时副本,就像我对NSArrays的NSDictionary一样?
目前,我这样做:
func addRecord(theRecord: DatabaseRecord, inTable tableName: String)
{
if var table = self.database[tableName]
{
table.append(theRecord)
self.database[tableName] = table
}
else
{
self.database[tableName] = [theRecord];
}
}
问题是:表的临时副本是两次。这非常低效。
答案 0 :(得分:3)
Swift数组使用值(复制)语义,但实际上它们被传递并指定为引用。只有在更改数组大小或重新排序元素时,才会真正复制数组。这被称为"懒惰副本"或"复制写入"。您不必害怕简单地分配这样的数组:
var temp = someBigArray
未复制。但是当你打电话时:
temp.append(someValue)
然后发生实际的复制。
在此行的代码中:
if var table = self.database[tableName]
数组未复制。
在这一行:
table.append(theRecord)
被复制。
在这一行:
self.database[tableName] = table
未复制,但字典中数组的引用计数减1,如果不存在对此数组的其他引用,则将其解除分配。 "表"然后将数组作为引用传递给" self.database [tableName]"。这里没有复制。
但Eric D的答案是正确的,通过直接在数组上调用append()(使用?运算符),创建的开销最小。这就是你应该这样做的方式:
self.database[tableName]?.append(theRecord)
但是也可以在append()中复制数组 - 如果必须扩展数组大小并且没有预先分配的空间,则会出现这种情况。这是因为数组总是必须有连续的内存。
因此,通过调用append(),可能会发生数组必须执行此操作:
所以通常你不必关心"效率低下"数组的副本 - 编译器知道的更好。
答案 1 :(得分:2)
我认为这是一个可以使用?
的可选绑定并直接附加值(这里使用三元运算符)的情况:
func addRecord(theRecord: DatabaseRecord, inTable tableName: String) {
self.database[tableName] == nil ? self.database[tableName] = [theRecord] : self.database[tableName]?.append(theRecord)
}