Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 如何避免在swift中创建对象数组的副本_Arrays_Swift_Dictionary - Fatal编程技术网

Arrays 如何避免在swift中创建对象数组的副本

Arrays 如何避免在swift中创建对象数组的副本,arrays,swift,dictionary,Arrays,Swift,Dictionary,我有一个数组字典,其中包含一种对象:数据库记录。 每个数组就像一个与字典中的键(表名)关联的表 我的问题是:如何更新表(删除记录、添加记录等),而不制作表的任何临时副本,就像使用NSArray字典一样 目前,我有: func addRecord(theRecord: DatabaseRecord, inTable tableName: String) { if var table = self.database[tableName] { table.append(

我有一个数组字典,其中包含一种对象:数据库记录。 每个数组就像一个与字典中的键(表名)关联的表

我的问题是:如何更新表(删除记录、添加记录等),而不制作表的任何临时副本,就像使用NSArray字典一样

目前,我有:

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];
    }
}

问题是:表的临时副本制作了两次。这是非常低效的。

我认为在这种情况下,您可以将可选绑定与
一起使用,并直接附加值(这里使用三元运算符):

Swift数组使用值(copy)语义,但实际上它们是作为引用传递和分配的。只有当数组大小发生变化或元素重新排序时,才会真正复制数组。这被称为“惰性复制”或“写时复制”。您不必害怕这样简单地分配数组:

var temp = someBigArray 
它不是复制的。但当你打电话时:

temp.append(someValue)
然后一个真实的拷贝发生了

在这一行的代码中:

if var table = self.database[tableName]
table.append(theRecord)
self.database[tableName] = table
阵列未被复制

在这方面:

if var table = self.database[tableName]
table.append(theRecord)
self.database[tableName] = table
它是复制的

在这方面:

if var table = self.database[tableName]
table.append(theRecord)
self.database[tableName] = table
它不会被复制,但字典中数组的引用计数会减少一,如果不存在对该数组的其他引用,则会取消分配该数组。然后将“table”数组作为引用传递到“self.database[tableName]”。这里没有副本

但是Eric D的答案是正确的,通过直接在数组上调用append()(使用?运算符),创建的开销最小。这是你应该做的:

self.database[tableName]?.append(theRecord)
但在append()中也可能发生复制数组get的情况——如果必须扩展数组大小并且没有预先分配的空间,则会出现这种情况。这是因为数组始终必须具有连续内存

因此,通过调用append(),数组可能必须执行以下操作:

  • 分配一个新的连续内存块,其当前计数大小加上至少一个或多个条目。(通常它会分配更多,以防万一将来会追加更多)
  • 将整个内容复制到新内存块(包括新条目)
  • 释放“旧”内存(这实际上更复杂,因为其他数组可能引用旧内存,在这种情况下,它不会被释放)

因此,通常您不必关心数组的“低效”拷贝—编译器知道得更好

感谢您提供了这个优雅的解决方案。那么,这在任何阶段都不会复制数据库的(大)表?对不起,我还不能投票,不客气。事实上,本版本中没有副本。第一部分检查nil,第二部分创建一个包含一个项的数组,第三部分仅在数组存在时附加到数组中(并且我们检查它是否这样做,它无论如何不会失败)。我认为这不是完全正确的,因为我们必须至少制作一个副本,以便与
nil
进行比较。我们正在使用getter,这将复制数组一次。如果我错了,请纠正我。(顺便说一句,拷贝在Swift中并没有那么糟糕。拷贝也是轻量级和快速的……如果self.database[tableName]?.append(theRecord)==nil{self.database[tableName]=[theRecord]},我也会像这样简化您的代码。这对功能没有影响,但我认为最好阅读。好吧,我坚信Swift不会为nil比较制作任何副本,但当然我没有证据,尽管我猜它可以在仪器中验证…--无论如何,在Swift中,值是在写入时复制的,这意味着例如“let b=a”实际上不会复制“a”,直到“b”"使用了,在这里我们对值不做任何处理。非常感谢您提供了这个非常详细的答案。我想,在数组中插入或删除元素时,NSArray必须执行这种巫毒。我一直相信NSArray能够实现得非常高效。所以我想我也可以相信swift编译器是高效的。但我只是希望避免像我在问题中所展示的代码那样的编程错误带来的开销。我知道,过早优化…但在目前的情况下,对事物如何工作的一点知识并不会带来任何伤害。因此,谢谢。我将第一个正确答案标记为解决问题+1给每个人。这可能是编译器更聪明足以看出初始数组在最后一步中也被分配了,temp只是,嗯,temp,非常不相关。在这种情况下,甚至没有出现一个副本。但我当然不确定这一点。