Как реализовать семантику Copy-on-Write (CoW) для пользовательского типа в Swift?

«Как реализовать семантику Copy-on-Write (CoW) для пользовательского типа в Swift?» — вопрос из категории Swift Core, который задают на 22% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Copy-on-Write (CoW) оптимизирует работу со value-типами, откладывая копирование данных до момента их реальной модификации. Реализуется через комбинацию struct и внутреннего ссылочного типа (class).

Базовая реализация:

// 1. Класс-хранилище (ссылочный тип)
final class Ref<T> {
    var value: T
    init(_ value: T) { self.value = value }
}

// 2. Публичная структура (value-тип) с CoW
struct CoWBox<T> {
    private var ref: Ref<T>

    init(_ value: T) {
        ref = Ref(value) // Создаем единственную ссылку
    }

    var value: T {
        get { ref.value } // Чтение — используем общие данные
        set {
            // Ключевой момент: копируем только если ссылка не уникальна
            if !isKnownUniquelyReferenced(&ref) {
                ref = Ref(newValue) // Создаем новое хранилище
                return
            }
            // Если ссылка уникальна — модифицируем существующие данные
            ref.value = newValue
        }
    }
}

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

  1. CoWBox — это структура. При присваивании (let box2 = box1) копируется только ссылка ref, а не сами данные.
  2. При чтении value данные используются напрямую из общего хранилища.
  3. При записи в value проверяется функция isKnownUniquelyReferenced(&ref). Она возвращает true, если на объект Ref есть только одна ссылка (этот экземпляр CoWBox — его единственный владелец).
    • Если true — можно безопасно менять данные «на месте».
    • Если false — значит, данные разделяют другие экземпляры CoWBox. Создается новый объект Ref с новым значением, и дальнейшие изменения не затронут другие копии.

Где используется: Именно так реализованы стандартные коллекции Swift (Array, Dictionary, Set, String), что делает их эффективными при передаче по значению.