Как проверить на Copy-on-Write

1. У Array адрес данных видно через withUnsafeBufferPointer. Копируем, смотрим адрес, меняем копию, смотрим снова.

var array = [1, 2, 3] var arrayCopy = array isSameAddress(array, arrayCopy) // true, смотрят на одни данные arrayCopy[0] = 10 isSameAddress(array, arrayCopy) // false, у arrayCopy своя копия print(array) print(arrayCopy) func isSameAddress(_ array: [Int], _ arrayCopy: [Int]) { // withUnsafeBufferPointer - указатель на элементы массива в памяти array.withUnsafeBufferPointer { arrayPointer in // У указателя есть: // baseAddress - адрес первого элемента // count - количество элементов arrayCopy.withUnsafeBufferPointer { arrayCopyPointer in // Сравниваем указатели на первые элементы print(arrayPointer.baseAddress == arrayCopyPointer.baseAddress) } } }

2. Для двух копий ContiguousArray проверка та же.

3. Для ArraySlice сравнивают две копии слайса. С самим массивом адрес совпадёт, только если слайс начинается с индекса 0.

4. У AttributedString открытого указателя нет, в отличие от массива. Но смысл тот же: копируем, меняем одну переменную, вторая не должна измениться.

5. У Set и Dictionary такого указателя нет. Но тут мы можем взглянуть в исходники:

internal struct _NativeSet<Element: Hashable> { internal var _storage: __RawSetStorage // class в куче } internal mutating func ensureUnique(isUnique: Bool, capacity: Int) -> Bool { if _fastPath(capacity <= self.capacity && isUnique) { return false } if isUnique { resize(capacity: capacity) return true } if capacity <= self.capacity { copy() // isUnique == false и capacity хватает: своя копия тех же данных return false } copyAndResize(capacity: capacity) // если capacity не хватает: тоже копируем, но после resize return true } internal mutating func copy() { let newStorage = _SetStorage.copy(original: _storage) // новый class в куче // ... копируем элементы ... _storage = result._storage // этот Set смотрит уже на новый объект }
NativeSet.swift

Ссылка на class в куче и copy() при isUnique == false как раз и есть copy-on-write.

6. У Data то же в Foundation. Перед изменением проверяют class в куче через isKnownUniquelyReferenced. Если ссылка не одна, делают mutableCopy.

mutating func ensureUniqueReference() { if !isKnownUniquelyReferenced(&_storage) { _storage = _storage.mutableCopy(_slice) } }
Data+Representation.swift