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

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

Ответ

Да, можно вручную реализовать семантику Copy-on-Write для кастомной структуры, чтобы оптимизировать производительность при работе с большими значениями.

Принцип работы: Данные хранятся в ссылочном типе (классе), а копирование буфера происходит только при попытке его изменения (записи), если на него есть несколько ссылок.

Пример реализации:

struct MyCoWStruct {
    // 1. Данные хранятся в приватном классе
    private class Storage {
        var data: [Int]
        init(data: [Int]) { self.data = data }
    }

    // 2. Единственная ссылка на хранилище
    private var storage: Storage

    init(data: [Int]) {
        storage = Storage(data: data)
    }

    // 3. Публичное свойство с логикой CoW
    var elements: [Int] {
        get { storage.data }
        set {
            // 4. Ключевая проверка: копируем только если хранилище разделяется
            if !isKnownUniquelyReferenced(&storage) {
                storage = Storage(data: storage.data)
            }
            storage.data = newValue
        }
    }

    // 5. Мутирующий метод также должен проверять уникальность ссылки
    mutating func append(_ value: Int) {
        if !isKnownUniquelyReferenced(&storage) {
            storage = Storage(data: storage.data)
        }
        storage.data.append(value)
    }
}

// Использование
var cow1 = MyCoWStruct(data: [1, 2, 3])
var cow2 = cow1 // На этом этапе копирования данных НЕТ

cow2.append(4) // Тут срабатывает CoW: создается новый Storage для cow2
print(cow1.elements) // [1, 2, 3]
print(cow2.elements) // [1, 2, 3, 4]

Ключевые элементы:

  • isKnownUniquelyReferenced(&object) — проверяет, является ли ссылка на объект уникальной.
  • Все мутирующие операции должны начинаться с этой проверки.
  • Стандартные типы Swift (Array, Dictionary, String) уже используют CoW под капотом.