Swift 與 Objective-C

Swift Copy-on-Write:用自製緩衝區觀察分離時機

實作以參考儲存區為基礎的小型緩衝區,確認共用後第一次寫入會分離,而獨佔儲存區的下一次寫入不會再次分離。

閱讀 2 分鐘
Swift Copy-on-Write:用自製緩衝區觀察分離時機 封面圖

Copy-on-Write是在維持值語意的同時延後複製儲存區的實作策略。修改共用儲存區之前先分離;若已獨佔,就直接修改。並非每個struct都會自動實作這項策略。

原理與設計判斷

標準集合的值語意與自訂儲存區的實作責任不同。這裡以private類別持有整數陣列,並在修改方法內用isKnownUniquelyReferenced檢查強參考是否唯一。所有修改路徑都必須遵守這項規則。 第一手資料

重現程式碼

IntBuffer指派後,先用identity確認兩者共用同一個Storage。向副本加入3時應分離儲存區,保留原本的陣列。接著加入4時,副本已獨佔Storage,因此不應再次分離。

這個獨立範例已於 2026-10-23 使用 Apple Swift 6.4,以 Swift 6 語言模式在 arm64 macOS 目標環境執行。不需要網路或額外套件。

下載完整 Swift 檔案

請在下載檔案的資料夾執行。檢查不符時,precondition 會中止程式。請勿使用 -Ounchecked,因為它會移除這些檢查。

swift -swift-version 6 swift-copy-on-write-prototype-pattern.swift
struct IntBuffer {
    private final class Storage {
        var values: [Int]
        init(_ values: [Int]) { self.values = values }
    }
    private var storage: Storage
    private(set) var detachments = 0
    init(_ values: [Int]) { storage = Storage(values) }
    var values: [Int] { storage.values }
    func sharesStorage(with other: IntBuffer) -> Bool {
        storage === other.storage
    }
    mutating func append(_ value: Int) {
        if !isKnownUniquelyReferenced(&storage) {
            storage = Storage(storage.values)
            detachments += 1
        }
        storage.values.append(value)
    }
}

let original = IntBuffer([1, 2])
var copy = original
precondition(copy.sharesStorage(with: original))
copy.append(3)
precondition(!copy.sharesStorage(with: original))
precondition(original.values == [1, 2] && copy.values == [1, 2, 3])
copy.append(4)
precondition(copy.detachments == 1 && copy.values == [1, 2, 3, 4])
print("shared-before=true shared-after=false detachments=1 original=[1,2] copy=[1,2,3,4]")

執行結果與解讀

shared-before=true shared-after=false detachments=1 original=[1,2] copy=[1,2,3,4]

detachments=1代表自製Storage包裝層分離了一次。原本維持[1,2],副本變成[1,2,3,4]。這不是底層Array緩衝區的實際配置次數,內部Array仍可能採用自己的CoW實作。

適用範圍與限制

這是單一執行流程的教學範例,不是執行緒安全的集合。唯一性檢查不是同步機制。以類別實例為元素的陣列也不會深層複製元素物件,因此不能說值型別取代了所有原型模式的用途。

接下來要確認的事

先區分哪些資料需要獨立副本、哪些可以共用。效能收益應以實際工作負載測量;沒有自訂需求時先用標準集合。內部參考的共用方式可參考class與struct實驗。

延伸實驗

來源與驗證