2015-08-04 3 views
2

У меня есть словарь массивов, которые содержат один вид объектов: записи базы данных. Каждый массив похож на таблицу, связанную с ключом (имя таблицы) в словаре.Как избежать создания копии массива объектов в swift

Моя проблема: Как обновить таблицу (удалить запись, добавить запись и т. Д.) Без какой-либо временной копии таблицы, как я бы сделал с NSDictionary NSArrays?

В настоящее время я:

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

Проблема заключается: временная копия таблицы производится дважды. Это довольно неэффективно.

ответ

2

Я думаю, что это тот случай, когда вы можете использовать опциональный связывание с ? и непосредственно присоединять значение (здесь с тройным оператором):

func addRecord(theRecord: DatabaseRecord, inTable tableName: String) { 

    self.database[tableName] == nil ? self.database[tableName] = [theRecord] : self.database[tableName]?.append(theRecord) 

} 
+0

Благодарим вас за это элегантное решение. Таким образом, это ни на какой стадии не скопирует (большую) таблицу базы данных? Мне жаль, что я еще не могу продвинуться. – John

+0

Добро пожаловать. Действительно, в этой версии нет копии. 1-я часть проверяет нуль, вторая часть создает массив с одним элементом, 3-я часть добавляет к массиву только в том случае, если он существует (и мы проверили, что он делает это, и это не сработает). – Moritz

+0

Я думаю, что это не совсем так, потому что есть хотя бы один экземпляр, который мы должны сделать для сравнения с 'nil'. Мы используем getter, и это скопирует массив один раз. Поправьте меня если я ошибаюсь. (Btw. Копии не так уж плохи в Swift. Копии также легкие и быстрые ... Я также облегчил бы ваш код, как этот 'if self.database [tableName] ?. append (theRecord) == nil {self. database [tableName] = [theRecord]} '. Это не имеет никакого значения для функциональности, но лучше читать по-моему. – DevAndArtist

3

Swift массивы используют значение (копия) семантику, но на самом деле они передаются и назначаются в качестве ссылок. Только когда происходит изменение размера массива или переупорядочения элементов, массив действительно копируется. Это называется «ленивая копия» или «копирование при записи». Вы не должны бояться, чтобы просто присвоить массив так:

var temp = someBigArray 

Это не скопирована. Но когда вы позвоните:

temp.append(someValue) 

Тогда происходит фактическая копия.

В коде в этой строке:

if var table = self.database[tableName] 

Массив не скопирована.

В этой строке:

table.append(theRecord) 

Это является скопирована.

В этой строке:

self.database[tableName] = table 

Это не скопирована, но арбитр подсчета массива в словаре уменьшается на единицу и, если нет других ссылок на этот массив не существует, то он освобождается. Затем массив «table» просто передается как ссылка в «self.database [tableName]». Здесь нет копии.

Но ответ Эрика D верен, вызвав append() непосредственно на массив (с помощью оператора?) Создается наименьшая служебная информация. Это, как вы должны это сделать:

self.database[tableName]?.append(theRecord) 

Но это может произойти также в Append(), что массив получить скопировали - что в случае, если размер массива должен быть расширен и нет заранее выделенного пространства , Это связано с тем, что массивы всегда должны иметь непрерывную память.

Так, позвонив Append() может случиться так, что массив должен сделать это:

  • выделить новый блок памяти смежный с текущим размером счета плюс, по крайней мере, один вход больше. (обычно он выделяет даже больше, чем это, на всякий случай, когда вы добавите больше в будущем)
  • скопируйте все содержимое в новый блок памяти (включая новую запись)
  • освободите «старую» память (это на самом деле сложнее, потому что другие массивы могут ссылаться на старую память, в этом случае она не отпущена)

Как правило, вам не нужно заботиться о «неэффективной» копии массивов - компилятор знает лучше.

+0

Большое спасибо за этот подробный ответ. Я полагаю, NSArray должен был делать этот вуду при вставке или удалении элементов в массивах. всегда доверяли NSArray, чтобы его реализовать, чтобы сделать это чрезвычайно эффективно. Поэтому, я думаю, я также могу доверять быстрому компилятору быть eff icient. Но я просто хочу избежать накладных расходов на ошибки программирования, такие как код, который я показал в своем вопросе. Я знаю, преждевременная оптимизация ... но в нынешней ситуации немного знаний о том, как все работает, не наносит никакого вреда. Так что спасибо тебе. Я отметил первый правильный ответ как решение проблемы +1 всем – John

+0

Может быть, что компилятор даже достаточно умен, чтобы увидеть, что начальный массив также назначен на последнем шаге, а temp - это просто, хорошо, тем не менее, не имеет значения. В этом случае также не выполняется даже одна копия. Но, конечно, я не уверен в этом. – Darko

Смежные вопросы