---
title: 'Nesne Kalıcılık Çerçeveleri'
source: 'https://academia.sh/tr/kurslar/ios-veri-ve-ag/nesne-kalicilik-cerceveleri'
course: 'Veri, Ağ ve Eşzamanlılık'
language: tr
updated: '2026-10-21T05:03:09+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Nesne kalıcılık çerçevesinin sorgular yerine nesnelerle çalıştığını ayırır'
    - 'Bağlamda yeni nesne oluşturup kaydetmenin yinelemeye duyarlı olduğunu ölçer'
    - 'Benzersizlik kısıtlı kaydın aynı değerde sağlam, farklı değerde sıraya duyarlı olduğunu doğrular'
    - 'Kısıt kaldırıldığında aynı kaydın sınıfının değiştiğini gösterir'
---

# Nesne Kalıcılık Çerçeveleri

Nesneleri bir bağlamda oluşturup kaydetmenin yinelemeye duyarlı, benzersizlik kısıtlı kaydın ise sıraya duyarlı olduğunun ve kısıtın sınıfı nasıl değiştirdiğinin ölçümü.

Önceki derste veritabanına satır ve birincil anahtar düzeyinde yaklaştık. Çoğu uygulama satırlarla değil, kendi tiplerinden **nesnelerle** düşünür: bir not, bir sipariş, bir kişi. **Nesne kalıcılık çerçevesi** bu nesneleri bir **bağlam** içinde izler, değişiklikleri biriktirir ve kaydedildiğinde alttaki depoya yazar. Satırın karşılığı nesnedir; birincil anahtarın karşılığı ise çoğu zaman bir benzersizlik kısıtıdır. Sorumuz değişmez: **bu işlem yinelenirse ya da sırası değişirse sonuç değişir mi?**

```swift
// Replay.swift — bir islemin yinelemeye ve siraya duyarliligini siniflandirir
struct Trial<State: Equatable & CustomStringConvertible> {
    let label: String
    let once: State
    let twice: State
    let forward: State
    let backward: State

    var sensitivity: String {
        switch (once != twice, forward != backward) {
        case (false, false): return "saglam"
        case (true, false): return "yinelemeye-duyarli"
        case (false, true): return "siraya-duyarli"
        case (true, true): return "cift-duyarli"
        }
    }

    func report() -> String {
        print("\(label) | bir=\(once) iki=\(twice) ab=\(forward) ba=\(backward) -> \(sensitivity)")
        return sensitivity
    }
}

func replay<State>(_ label: String, from start: State, _ a: (State) -> State, then b: (State) -> State) -> Trial<State> {
    Trial(label: label, once: a(start), twice: a(a(start)), forward: b(a(start)), backward: a(b(start)))
}

func countSensitivities(_ results: [String]) {
    for name in ["saglam", "yinelemeye-duyarli", "siraya-duyarli", "cift-duyarli"] {
        print("\(name): \(results.filter { $0 == name }.count)")
    }
}
```

`bir` işlemin başlangıç durumuna bir kez, `iki` iki kez uygulanmasıdır; `ab` önce `a` sonra `b`, `ba` ise tersi sıradır. Model bir bağlamın saf Swift karşılığıdır. Çerçevenin kendisi değildir; yalnız bir nesneyi oluşturup kaydetmenin sonucunu kurar.

## Bağlam, Nesne ve Kayıt

Bir bağlam, bellekte yaşayan nesneler kümesinin yöneticisidir. Uygulama yeni bir nesne oluşturur, bağlama ekler ve kaydeder. Kaydedilene kadar değişiklik yalnız bellektedir. İki yazım dili vardır: eski çerçeve bir kalıcı kap ve bir yönetilen nesne bağlamı kullanır; yeni çerçeve `@Model` ile işaretlenmiş sınıflar ve bir model bağlamı kullanır.

```swift
import SwiftData

@Model
final class Note {
    @Attribute(.unique) var id: String
    var body: String

    init(id: String, body: String) {
        self.id = id
        self.body = body
    }
}

let container = try ModelContainer(for: Note.self)
let context = ModelContext(container)
context.insert(Note(id: "k1", body: "a1"))
try context.save()
```

Bu parça KAYNAK'tır; bir model kabı ve disk gerektirdiği için burada koşmaz. `@Attribute(.unique)` bir niteliği benzersiz yapar: aynı `id` ile gelen ikinci nesne yeni bir kayıt açmaz, mevcut kaydı günceller. Nitelik kısıtsız bırakılırsa her ekleme yeni bir kayıt olur. Eski çerçevede aynı amaç benzersizlik kısıtıyla ve bir birleştirme politikasıyla sağlanır. Bu dersin ölçümü iki durumu karşılaştırır.

## Bağlamın Modeli

Model, kayıtların bir listesini tutar. Her kayıt bir anahtar ve bir değerdir. Kısıt açıksa aynı anahtarla gelen kayıt mevcut kaydın yerine geçer; kapalıysa yeni bir kayıt olarak eklenir. Anahtarsız oluşturulan nesneye bağlam kendi anahtarını verir.

```swift
// ContextModel.swift — bir baglamin saf Swift modeli
struct ContextBox: Equatable, CustomStringConvertible {
    struct Entry {
        let key: String
        var value: String
    }

    private(set) var entries: [Entry] = []
    private(set) var nextId = 1
    let enforcesUnique: Bool

    init(enforcesUnique: Bool = true) {
        self.enforcesUnique = enforcesUnique
    }

    var description: String {
        entries.isEmpty ? "-" : entries.map { "\($0.key)=\($0.value)" }.joined(separator: ",")
    }

    static func == (lhs: ContextBox, rhs: ContextBox) -> Bool {
        lhs.description == rhs.description
    }

    mutating func create(_ value: String) {
        entries.append(Entry(key: "obj\(nextId)", value: value))
        nextId += 1
    }

    mutating func save(_ value: String, key: String) {
        if enforcesUnique, let index = entries.firstIndex(where: { $0.key == key }) {
            entries[index].value = value
        } else {
            entries.append(Entry(key: key, value: value))
        }
    }
}

func creating(_ value: String) -> (ContextBox) -> ContextBox {
    { context in
        var next = context
        next.create(value)
        return next
    }
}

func saving(_ value: String, key: String) -> (ContextBox) -> ContextBox {
    { context in
        var next = context
        next.save(value, key: key)
        return next
    }
}
```

**KL12.** Model, aynı benzersiz anahtar geldiğinde son yazanın kazandığını varsayar: mevcut kaydın değeri yenisiyle değişir. Çerçevenin gerçek birleştirme politikası ve bunun ayarları ölçülmedi.

**KL13.** Model, her işlemi eklemek ve hemen kaydetmek olarak kurar. Kaydedilmemiş değişiklikler, geri alma ve birden çok bağlam kurulmadı.

## Dört İşlemin Ölçümü

Dört işlem kurulur. Birincisi aynı değerle yeni bir nesne oluşturmaktır. İkincisi iki farklı değerle iki nesne oluşturmaktır. Üçüncüsü benzersiz bir anahtara aynı değeri iki kez kaydetmektir. Dördüncüsü aynı anahtara iki farklı değer kaydetmektir.

```swift
// main.swift — nesne olusturma ve benzersiz kayit
let createSame = replay("olustur-ayni-deger", from: ContextBox(), creating("a1"), then: creating("a1")).report()
let createTwo = replay("olustur-iki-deger", from: ContextBox(), creating("a1"), then: creating("b2")).report()
let uniqueSame = replay("kisitli-ayni-deger", from: ContextBox(), saving("a1", key: "k1"), then: saving("a1", key: "k1")).report()
let uniqueTwo = replay("kisitli-iki-deger", from: ContextBox(), saving("a1", key: "k1"), then: saving("b2", key: "k1")).report()

countSensitivities([createSame, createTwo, uniqueSame, uniqueTwo])
```

```
olustur-ayni-deger | bir=obj1=a1 iki=obj1=a1,obj2=a1 ab=obj1=a1,obj2=a1 ba=obj1=a1,obj2=a1 -> yinelemeye-duyarli
olustur-iki-deger | bir=obj1=a1 iki=obj1=a1,obj2=a1 ab=obj1=a1,obj2=b2 ba=obj1=b2,obj2=a1 -> cift-duyarli
kisitli-ayni-deger | bir=k1=a1 iki=k1=a1 ab=k1=a1 ba=k1=a1 -> saglam
kisitli-iki-deger | bir=k1=a1 iki=k1=a1 ab=k1=b2 ba=k1=a1 -> siraya-duyarli
saglam: 1
yinelemeye-duyarli: 1
siraya-duyarli: 1
cift-duyarli: 1
```

Aynı değerle yeni nesne oluşturmak yinelendiğinde iki nesne bırakır: `obj1=a1` ve `obj1=a1,obj2=a1`. Sıra anlamsızdır. Sınıf **yinelemeye duyarlı**dır. Bir ekranın yeniden görünmesiyle ya da bir yeniden denemeyle ikinci kez koşan oluşturma kodu, kullanıcıya çift kayıt olarak yansır.

İki farklı değerle oluşturma hem yinelemeyi hem sırayı ayrıştırır: kimlikler değerlere farklı dağılır. Sınıf **çift duyarlı**dır.

Benzersiz anahtara aynı değeri iki kez kaydetmek hiçbir şeyi değiştirmez. Kısıt, yinelemeyi sağlam kılar. Sınıf **sağlam**dır.

Aynı anahtara iki farklı değer kaydedilince ise sonucu sıra belirler: `ab` `b2`, `ba` `a1`. Kısıt çift kaydı önler, ama çakışmada hangi değerin kazanacağı sıraya kalır. Sınıf **sıraya duyarlı**dır.

Sayım her sınıftan birer tanedir.

## Şema Göçü

Bir uygulamanın nesne tipi sürümler arasında değişir: bir nitelik eklenir, bir ad değişir, iki tip birleşir. Kullanıcının aygıtında ise eski sürümün yazdığı veri durur. **Şema göçü**, eski şemayla yazılmış veriyi yeni şemaya taşıyan adımdır. Basit değişiklikler, örneğin bir niteliğin eklenmesi, çerçeve tarafından kendiliğinden yapılabilir; bir adın değişmesi ya da iki alanın birleşmesi gibi değişiklikler açık bir eşleme gerektirir.

Şema göçü bu dersin modelinde kurulmadı. Çünkü sonucu depodaki eski veriye ve sürüm sırasına bağlıdır; bir bağlamın bellekteki hâlinden okunamaz. Burada KAYNAK ve düzyazı olarak kalır. Pratik kural basittir: şemayı değiştiren her sürüm, eski sürümün yazdığı bir veriyle denenmeden yayımlanmaz.

## Sık Yapılan Hatalar

- Oluşturma kodunu bir ekranın görünme olayına bağlamak. Ekran her göründüğünde yeni bir nesne doğar.
- Kayıt için doğal bir kimlik varken bunu benzersiz yapmamak. Yeniden deneme çiftlenir.
- Benzersizlik kısıtının çakışmayı çözdüğünü sanmak. Çakışmada kazananı sıra belirler.
- Kaydetmeyi unutmak. Değişiklik bellektedir ve uygulama kapanınca kaybolur.
- Bağlamı iş parçacıkları arasında paylaşmak. Çerçeve bunu desteklemez; her iş parçacığı kendi bağlamını kullanır.
- Şemayı değiştirip eski veriyle denemeden yayımlamak.

## Sınırlayıcı Ölçüm

Kısıtın katkısını ayırmak için aynı kayıt çiftini kısıt kapalıyken ölçelim. Kısıt kapalıysa aynı anahtarla gelen kayıt mevcut kaydın yerine geçmez; yeni bir kayıt olur.

```swift
// main.swift — kisit acik ve kapali
let openSame = replay("kisitsiz-ayni-deger", from: ContextBox(enforcesUnique: false), saving("a1", key: "k1"), then: saving("a1", key: "k1")).report()
let openTwo = replay("kisitsiz-iki-deger", from: ContextBox(enforcesUnique: false), saving("a1", key: "k1"), then: saving("b2", key: "k1")).report()
let closedSame = replay("kisitli-ayni-deger-yeniden", from: ContextBox(), saving("a1", key: "k1"), then: saving("a1", key: "k1")).report()

countSensitivities([openSame, openTwo, closedSame])
```

```
kisitsiz-ayni-deger | bir=k1=a1 iki=k1=a1,k1=a1 ab=k1=a1,k1=a1 ba=k1=a1,k1=a1 -> yinelemeye-duyarli
kisitsiz-iki-deger | bir=k1=a1 iki=k1=a1,k1=a1 ab=k1=a1,k1=b2 ba=k1=b2,k1=a1 -> cift-duyarli
kisitli-ayni-deger-yeniden | bir=k1=a1 iki=k1=a1 ab=k1=a1 ba=k1=a1 -> saglam
saglam: 1
yinelemeye-duyarli: 1
siraya-duyarli: 0
cift-duyarli: 1
```

Aynı kayıt çifti, kısıt kapalıyken yinelemeye duyarlı, açıkken sağlam çıktı. İki değerli çift ise kısıtsız çift duyarlı, kısıtlı sıraya duyarlıydı. Kısıt yinelemeyi çözdü ve iki satırı bir satıra indirdi; sırayı çözmedi.

Bu ölçümün sınırı KL12'dir. Model, çakışmada son yazanın kazanacağını varsayar. Gerçek çerçevede birleştirme politikası ayarlanabilir ve bazı politikalar mevcut kaydı korur; bu derste hiçbiri ölçülmedi. Politika değişirse `ab` ile `ba` yer değiştirebilir, ama ikisinin eşit olmayacağı sonucu değişmez.

## Gerçek Uygulamada Nerede Görülür

Nesne kalıcılık çerçeveleri, bir nesne grafiğini sizin yerinize satırlara çevirir; bu rahatlık, yinelemenin görünmez hâle gelmesinin de nedenidir. Kullanıcı bir not oluşturduğunda uygulama yeni bir nesne yaratır ve bağlamı kaydeder. Aynı kod yolu bir yeniden denemede ya da bir ekran yenilemesinde tekrar çalışırsa, çerçeve her seferinde yeni bir nesne üretir. `olustur-ayni-deger` satırında gördüğümüz çoğaltma budur: iki çağrı, iki nesne. Liste ekranında aynı not iki kez durur ve hiçbir hata verilmemiştir.

Benzersizlik kısıtı bu çoğaltmayı engeller. Bir nitelik benzersiz olarak işaretlenince, aynı değerli ikinci nesne eklenemez; çerçeve ya yeni nesneyi var olanla birleştirir ya da kaydı reddeder. `kisitli-ayni-deger` satırında iki çağrı tek nesne verir ve sınıf sağlam olur. Ama kısıt, iki farklı değerin aynı benzersiz anahtarla gelmesini çözmez: `kisitli-iki-deger` satırında kalan değer sıraya bağlıdır. Kısıt yinelemeyi çözer, sırayı çözmez.

Gerçek bir uygulamada bu, sunucudan gelen kayıtların yerel kopyayla eşleştirilmesinde görülür. Sunucu her kaydın kararlı bir kimliğini verir; yerel kayıt bu kimlikle benzersiz kılınırsa, aynı yanıtın iki kez işlenmesi bir kayıt üretir. Kimlik olmadan yerel nesne yeniden oluşturulur ve iki kopya doğar.

## Yanlış Kurulum ve Düzeltmesi

Yaygın yanlış kurulum, benzersizliği kodda kontrol etmektir: "bu değerli nesne var mı, yoksa oluştur". Kontrol ile oluşturma arasında kalan aralık, iki işlemin ikisinin de "yok" yanıtı alabildiği yerdir. Ayrıca kontrol yalnız bağlamdaki nesnelere bakar; başka bir bağlamda ya da henüz kaydedilmemiş bir nesne gözden kaçar.

Düzeltme, benzersizliği şemanın bir parçası yapmaktır. Kısıt depolama katmanında durur ve her yazmada uygulanır; kodun hangi yoldan geldiği önemli olmaz. Çerçevenin birleştirme politikası da burada belirleyicidir. Politika, çakışmada hangi değerin kalacağını söyler. Modelimiz son yazanın kazandığını varsaydı, ve bu KL12 olarak kayıtlıdır. Başka bir politika mevcut kaydı korursa `ab` ile `ba` yer değiştirir; ama iki sıranın aynı sonucu vermediği gerçeği değişmez.

İkinci yanlış, kaydetmeyi unutmaktır. Nesneyi oluşturup bağlamı kaydetmeyen kod, değişikliğin kalıcı olduğunu sanır. Uygulama kapanınca nesne kaybolur. Modelimiz her işlemi ekleyip hemen kaydeder; KL13 bunu kaydeder. Gerçek kodda kaydetme çağrısını kimin yaptığı, iş yapan her yerde açıkça belirlenmelidir.

## KAYNAK Parçayı Okumak

Dersin başındaki adsız parça, bir nesne tipini tanımlar, bir bağlam açar, nesneyi oluşturur ve kaydeder. Nesne tipi, kalıcı olacak niteliklerini belirtir ve çerçeve bunları tabloya çevirir. Parçanın gösterdiği asıl şey, sizin "kaydet" dediğiniz çağrının aslında bir işlem sınırı olmasıdır: bu çağrıya kadar yapılan değişiklikler bellekte durur ve çağrıyla birlikte diske gider.

Model bunu tek adıma indirgedi ve kaydedilmemiş değişiklikleri, geri almayı ve birden çok bağlamı kurmadı. Bunlar gerçek uygulamada önemli durumlardır; ancak ölçtüğümüz soru, yani aynı işlemin yinelenmesi ve sırasının değişmesi, bu sadeleştirmeyle de anlamlı kalır. Şema göçü kısmında anlatılan sürüm değişikliği ise ayrı bir konudur ve bu derste yalnız anlatılır, ölçülmez.

## Ölçümden Tasarıma

Nesne çerçevesinin ölçümü, kısıtın ne yaptığını ve ne yapmadığını ayırır. Kısıtsız durumda yinelenen oluşturma çoğaltma yaratır; kısıtla aynı çağrılar tek nesne verir. Ama kısıt yalnız eşitliği çözer. Aynı anahtarla gelen iki farklı değerde hangisinin kalacağı, çerçevenin birleştirme politikasına bağlıdır. Dolayısıyla tasarım iki kararı ayrı ayrı vermeyi gerektirir: hangi nitelik kimliği belirler ve çakışmada hangi değer kalır.

Kimlik seçimi bir veri modeli kararıdır. Sunucudan gelen kayıtlar için sunucunun verdiği kimlik doğal adaydır. Kullanıcının oluşturduğu kayıtlar için uygulama bir kimlik üretir ve bu kimliği oluşturma anında, bir kez, kaydın kendisine yazar. Kimliği her çağrıda yeniden üretmek, kısıtı anlamsız kılar, çünkü her çağrı farklı bir kimlik taşır ve hiçbir çakışma doğmaz.

Politika kararı ise ürün kararıdır. Son yazanın kazanması basittir ve veri kaybı riski taşır; mevcut kaydı korumak güvenlidir ama yeni bilgiyi atar; alan alan birleştirmek en iyi sonucu verir ve en çok iş ister. Hangisinin doğru olduğunu ölçüm söylemez. Ölçüm yalnız seçilen politikanın hangi sınıfa yol açtığını gösterir.

Bir de şema göçü vardır. Veri tipi sürümler arasında değişir ve eski sürümün yazdığı veri yeni şemaya taşınmalıdır. Basit eklemeler çerçeve tarafından otomatik yapılabilir; ad değişikliği ve birleştirme açık bir eşleme ister. Göç, her sürümde bir kez koşan bir işlemdir. Yinelenirse ya da yarıda kesilirse, veri ya eski ya yeni biçimde kalmalıdır; yarım bir göç, ölçtüğümüz yinelemeye duyarlılığın en pahalı biçimidir.

Ölçümün dışında kalan bir durumu da not etmek gerekir: ilişkili nesneler. Bir not ile etiketleri arasında ilişki varsa, notu silmek etiketlere ne yapar, etiketi silmek nota ne yapar? Çerçeve bu sorunun cevabını silme kuralı olarak ister: ilişkiyi kopar, bağlı nesneleri de sil ya da silmeyi reddet. Kural verilmezse varsayılan davranış devreye girer ve çoğu zaman yetim nesneler kalır. Bu dersin modeli ilişkileri kurmaz; ama gerçek bir şemada bu karar, benzersizlik kısıtı kadar önemlidir ve aynı özenle yazılmalıdır.

Silme kuralının ölçümle bağlantısı doğrudandır. Bir silme işlemi yinelenirse, ikinci silme zaten olmayan bir nesneyi hedefler; çerçevenin bu durumda hata verip vermediği, silmenin yinelemeye karşı sağlam olup olmadığını belirler. Bunu ölçmeden varsaymamak, bu dersin genel alışkanlığıdır.

## Özet

- Nesne kalıcılık çerçevesi, nesneleri bir bağlamda izler ve kaydedildiğinde depoya yazar.
- Aynı değerle yeni nesne oluşturmak yinelendiğinde iki nesne bırakır (`obj1=a1` sonra `obj1=a1,obj2=a1`); sınıf yinelemeye duyarlıdır.
- Benzersizlik kısıtlı kayıt aynı değerde sağlamdır, aynı anahtara farklı değerde sıraya duyarlıdır (`ab` `b2`, `ba` `a1`).
- Kısıt kaldırılırsa aynı kayıt çifti yinelemeye duyarlı hâle gelir; iki değerli çift çift duyarlı olur.
- Şema göçü ve birleştirme politikası ölçülmedi; KAYNAK ve düzyazı olarak kaldı.
- Bu dersin duyarlılığı: **yinelemeye duyarlı**.

## Sonraki Adım

Şimdiye kadar tüm veri tek bir aygıtta duruyordu. Sıradaki derste, Bulut Eşitleme, aynı kaydı iki aygıtın yazdığı durumu ölçeceğiz ve aygıtların değerlerinin farklı sırayla gelmesinin sonucu nasıl değiştirdiğini göreceğiz.
