Что такое Copy-on-Write (CoW) в Swift?

Ответ

Copy-on-Write (CoW) — это стратегия оптимизации, при которой копирование данных структуры или коллекции происходит не в момент присваивания, а только при первой попытке её модификации.

Как это работает в Swift:

var originalArray = [1, 2, 3]
var copiedArray = originalArray // Нет реального копирования. Оба массива ссылаются на один буфер.

// Модификация триггерит копирование:
copiedArray.append(4) // Здесь создается физическая копия данных для `copiedArray`.

print(originalArray) // [1, 2, 3]
print(copiedArray)   // [1, 2, 3, 4]

Ключевые аспекты:

  • Экономия ресурсов: Память не расходуется на копии, которые никогда не будут изменены.
  • Автоматизация: Swift автоматически реализует CoW для своих стандартных типов-значений (Array, Dictionary, Set, String) и пользовательских структур, хранящих данные в куче.
  • Ручная реализация: Для собственных структур, которым нужна эта оптимизация, можно использовать isKnownUniquelyReferenced для проверки уникальности ссылки на хранимые данные.
    
    final class Ref<T> {
    var value: T
    init(_ value: T) { self.value = value }
    }

struct MyCoWStruct { private var ref: Ref var value: T { get { ref.value } set { // Копируем буфер только если на него больше одной ссылки if !isKnownUniquelyReferenced(&ref) { ref = Ref(newValue) } else { ref.value = newValue } } } init(_ value: T) { self.ref = Ref(value) } }

Ответ 18+ 🔞

А, слушай, вот эта штука — Copy-on-Write, CoW, блядь. Ну, типа, хитрая оптимизация, чтобы не копировать тонны данных просто так, на ровном месте. Представь: у тебя здоровенный массив, как слон, и ты его присваиваешь в другую переменную. Так вот, если ты его не трогаешь, то копии-то и нет, ёпта! Обе переменные тихо, мирно смотрят на один и тот же кусок памяти, как два мудака на одну бутылку.

Как эта магия в Swift работает, на примере:

var originalArray = [1, 2, 3]
var copiedArray = originalArray // Никакого реального копирования! Оба смотрят на одно и то же, как ворона на сыр.

// А вот тут начинается пиздец, то есть модификация:
copiedArray.append(4) // БАБАХ! Вот тут-то Swift и создаёт настоящую, отдельную копию данных для `copiedArray`. До этого всё было по-братски.

print(originalArray) // [1, 2, 3] — его не тронули, красава.
print(copiedArray)   // [1, 2, 3, 4] — а вот этот уже со своим багажом.

Суть, если по полочкам:

  • Экономия, мать её: Зачем тратить память и процессор на копии, которые, может, никогда и не понадобятся? Вот именно, нихуя не зачем. CoW ждёт, пока ты реально не полезешь что-то менять.
  • Всё само: Swift, падла умная, сама это делает для своих стандартных структур — Array, Dictionary, Set, String. Сиди и не парься.
  • Самоделки: А если ты свою структуру наколхозил, и она внутри хранит ссылочные данные (объект в куче), то можно и ручками провернуть. Используй isKnownUniquelyReferenced, чтобы понять, один ты такой умный на эту кучу смотришь, или уже очередь выстроилась.
    
    final class Ref<T> {
    var value: T
    init(_ value: T) { self.value = value }
    }

struct MyCoWStruct { private var ref: Ref var value: T { get { ref.value } set { // Копируем буфер только если на него больше одной ссылки if !isKnownUniquelyReferenced(&ref) { ref = Ref(newValue) // Ага, щас скопируем, блядь, своё собственное! } else { ref.value = newValue // Один в поле воин, можно менять на месте. } } } init(_ value: T) { self.ref = Ref(value) } }


Вот и вся философия. Не делай работу, пока тебя об этом не попросят. Мудро, блядь.