---
title: 'Otomatik Referans Sayımı'
source: 'https://academia.sh/tr/kurslar/swift/otomatik-referans-sayimi'
course: 'Swift Dili'
language: tr
updated: '2026-10-21T05:03:12+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - "Son güçlü referans bırakılınca deinit'in çalıştığı noktayı print sırasından okur"
    - 'Kapsam sonu, nil ataması, diziden çıkarma ve döngü yinelemesinde deinit anını ölçer'
    - "İkinci bir referansın deinit'i ilk bırakmadan sonraya ertelediğini gösterir"
    - "Üst düzey bir let'in tuttuğu nesnenin deinit'inin çalışmadığını ölçer"
---

# Otomatik Referans Sayımı

Sınıf örneğinin son güçlü referansı bırakıldığı anda deinit'in çalıştığını dört bırakma yolunda ölçer ve ikinci bir referansın bu anı ertelediğini gösterir.

Önceki ders erişim düzeylerinin bir adı kimin görebildiğini değiştirdiğini, ama anı değiştirmediğini ölçtü: gizli bir `lazy` önbellek, `private` olsa da ilk kullanımda kuruluyordu. Bu ders görünürlükten çıkıp bir nesnenin ne zaman yok edildiğine geçer. Sınıf örnekleri **otomatik referans sayımı (ARC)** ile yönetilir: her örnek üzerindeki güçlü referansların sayısı tutulur ve bu sayı sıfıra düştüğü anda örnek yok edilir. Yok edilirken sınıfın `deinit` gövdesi koşar. Soru bu kursun sorusudur: `deinit` gövdesi ne zaman değerlendiriliyor?

Önceki müfredatlarda ömrün nerede bittiği ve belleği kimin sahiplendiği sorulmuştu. Bu ders ikisini de kategori yapmaz. Ömrün sınırı ya da sahibi ölçülmez; ölçülen, `deinit` gövdesinin hangi satırdan sonra ve kaç kez koştuğudur, yani an. Önce çekirdek verilir. `Probe`, bir ifadenin kaç kez değerlendirildiğini ve bunun kullanımdan önce mi sonra mı olduğunu kaydeder; `tally` dört anı sayar.

```swift
// Probe.swift — bir ifadenin ne zaman degerlendirildigini kaydeder
final class Probe {
    let label: String
    private(set) var evaluations = 0
    private(set) var uses = 0
    private var evaluatedBeforeUse = false

    init(_ label: String) {
        self.label = label
    }

    func eval<T>(_ value: T) -> T {
        evaluations += 1
        if uses == 0 { evaluatedBeforeUse = true }
        return value
    }

    func use<T>(_ access: () -> T) -> T {
        uses += 1
        return access()
    }

    var moment: String {
        if evaluations == 0 { return "hic" }
        if evaluations > 1 { return "her-kullanimda" }
        return evaluatedBeforeUse ? "hemen" : "ilk-kullanimda"
    }

    func report() {
        print("\(label): \(evaluations) degerlendirme, \(uses) kullanim -> \(moment)")
    }
}

func tally(_ probes: [Probe]) {
    for moment in ["hemen", "ilk-kullanimda", "her-kullanimda", "hic"] {
        let count = probes.filter { $0.moment == moment }.count
        print("\(moment): \(count)")
    }
}
```


Ölçülecek sınıf `Session`'dır. `deinit` gövdesi önce bir satır basar, sonra sahibi olan `Probe`'a `eval` ile haber verir. Böylece hem `print` sırası hem de `Probe` sayacı aynı olayı gösterir.

```swift
// Session.swift — deinit'inde Probe'a yazan sinif
final class Session {
    let name: String
    let owner: Probe

    init(_ name: String, owner: Probe) {
        self.name = name
        self.owner = owner
    }

    deinit {
        print("deinit \(name)")
        _ = owner.eval(name)
    }
}
```


## Dört Bırakma Yolu

Birinci ölçüm bir `Session` örneğini dört farklı yolla bırakır. İlk yol bir `do` kapsamının sonudur. İkincisi isteğe bağlı bir değişkene `nil` atamaktır. Üçüncüsü diziden `removeLast()` ile çıkarmaktır. Dördüncüsü bir `for` döngüsünün her yinelemesinde yeni örnek kurmaktır. Her yol en az iki kez çalışır, çünkü `Probe`'un kuralı `hic` dışındaki her gözlem için en az iki kullanım ister. Kural sayar, niyeti okumaz.

```swift
// main.swift — deinit hangi birakista kosar
let scopeEnd = Probe("kapsam-sonu")
let niled = Probe("nil-atamasi")
let removed = Probe("diziden-cikarma")
let looped = Probe("dongu-yinelemesi")

for round in 1...2 {
    _ = scopeEnd.use {
        do {
            let temp = Session("kapsam-\(round)", owner: scopeEnd)
            print("kullanildi \(temp.name)")
        }
    }
}

for round in 1...2 {
    var held: Session? = Session("nil-\(round)", owner: niled)
    _ = niled.use { held = nil }
    print("sonra \(held == nil)")
}

var list = [Session("dizi-1", owner: removed), Session("dizi-2", owner: removed)]
_ = removed.use { list.removeLast() }
_ = removed.use { list.removeLast() }
print("dizide kalan \(list.count)")

for round in 1...3 {
    let item = Session("dongu-\(round)", owner: looped)
    _ = looped.use { item.name }
}

let probes = [scopeEnd, niled, removed, looped]
for probe in probes {
    probe.report()
}
tally(probes)
```

```
kullanildi kapsam-1
deinit kapsam-1
kullanildi kapsam-2
deinit kapsam-2
deinit nil-1
sonra true
deinit nil-2
sonra true
deinit dizi-2
deinit dizi-1
dizide kalan 0
deinit dongu-1
deinit dongu-2
deinit dongu-3
kapsam-sonu: 2 degerlendirme, 2 kullanim -> her-kullanimda
nil-atamasi: 2 degerlendirme, 2 kullanim -> her-kullanimda
diziden-cikarma: 2 degerlendirme, 2 kullanim -> her-kullanimda
dongu-yinelemesi: 3 degerlendirme, 3 kullanim -> her-kullanimda
hemen: 0
ilk-kullanimda: 0
her-kullanimda: 4
hic: 0
```


Çıktıda önce `print` satırlarının sırasına bakılır. `kullanildi kapsam-1` satırı `deinit kapsam-1` satırından önce gelir: ölçülen koşumda örnek kapsamın sonunda yok edildi ve `deinit` satırı kapsam çıkışında göründü. `nil` atamasında `deinit` atamanın içinde koşar, ardından gelen `sonra true` satırı bunu doğrular. Dizide iki örnek vardır; `removeLast()` sondakini çıkarır, bu yüzden `dizi-2` `dizi-1`'den önce yok edilir. Döngüde üç yineleme üç ayrı `deinit` üretir ve her `deinit` bir sonraki yinelemeden önce biter.

Dört `Probe`'un hepsi `her-kullanimda` der. İlk üçünde iki tur olduğu için iki değerlendirme, döngüde üç tur olduğu için üç değerlendirme sayılır. `deinit` gövdesi bir örnek her yok edildiğinde yeniden koşar ve her yok ediliş yeni bir örneğe aittir. Bu dersin anı bu yüzden **her kullanımda**dır. `tally` çıktısında `hemen`, `ilk-kullanimda` ve `hic` sıfırdır.

## Fonksiyon Sınırı

Referansı yalnız değişkenler tutmaz; bir fonksiyona parametre olarak geçen örnek de çağrı süresince canlıdır. İkinci ölçüm iki durumu ayırır. Birinde fonksiyon örneği üretir ve çağıran tutar. Ötekinde üretilen örnek hiçbir değişkene bağlanmaz, yalnız bir ifadenin ortasında yaşar.

```swift
// main.swift — fonksiyon sinirinda referans
func inspect(_ session: Session) -> String {
    session.name
}

func make(_ name: String, owner: Probe) -> Session {
    Session(name, owner: owner)
}

let crossing = Probe("fonksiyon-siniri")

for round in 1...2 {
    let made = make("uretilen-\(round)", owner: crossing)
    _ = crossing.use { inspect(made) }
    print("tur bitti \(round)")
}

for round in 1...2 {
    _ = crossing.use { inspect(make("gecici-\(round)", owner: crossing)) }
    print("gecici tur bitti \(round)")
}

crossing.report()
```

```
tur bitti 1
deinit uretilen-1
tur bitti 2
deinit uretilen-2
deinit gecici-1
gecici tur bitti 1
deinit gecici-2
gecici tur bitti 2
fonksiyon-siniri: 4 degerlendirme, 4 kullanim -> her-kullanimda
```

Birinci döngüde `tur bitti 1` satırı `deinit uretilen-1` satırından önce gelir. `inspect` çağrısı süresince örnek canlıdır ve çağrı örneğin ömrünü uzatmaz; örneğin sahibi hâlâ `made` sabitidir ve `deinit` yinelemenin sonunda, `made` kapsamdan çıkarken koşar. İkinci döngüde ise `make` ile üretilen örnek hiçbir ada bağlanmaz. Ölçülen koşumda örnek çağıran ifade biterken bırakıldı ve `deinit gecici-1` satırı `gecici tur bitti 1` satırından önce görünür. İki döngü birlikte `fonksiyon-siniri` için dört değerlendirme ve dört kullanım kaydeder. Yani bir fonksiyona örnek geçirmek ömrü uzatmaz; ömrü uzatan, örneği bir adda ya da bir özellikte saklamaktır.

## Zincirleme Bırakma

Bir örnek başka bir örneği özelliğinde tutabilir. Bu durumda dıştaki örneğin yok edilmesi içtekinin son referansını da bırakır. Üçüncü ölçüm iki zinciri birlikte kurar: `Holder` bir `Session` tutar, `Car` ise `Vehicle` sınıfından türer ve iki sınıfın da `deinit` gövdesi vardır. Soru, hangi `deinit` gövdesinin önce koştuğudur.

```swift
// main.swift — ozellikteki ornek ve alt sinif zinciri
final class Holder {
    let name: String
    let child: Session

    init(_ name: String, owner: Probe) {
        self.name = name
        child = Session("cocuk-\(name)", owner: owner)
    }

    deinit {
        print("deinit \(name)")
    }
}

class Vehicle {
    let owner: Probe

    init(owner: Probe) {
        self.owner = owner
    }

    deinit {
        print("deinit ust-sinif")
        _ = owner.eval("ust")
    }
}

final class Car: Vehicle {
    deinit {
        print("deinit alt-sinif")
        _ = owner.eval("alt")
    }
}

let nested = Probe("ozellikteki-ornek")
let inherited = Probe("ust-sinif-zinciri")

for round in 1...2 {
    var holder: Holder? = Holder("sahip-\(round)", owner: nested)
    _ = nested.use { holder = nil }
}

for _ in 1...2 {
    var car: Car? = Car(owner: inherited)
    _ = inherited.use { car = nil }
}

nested.report()
inherited.report()
```

```
deinit sahip-1
deinit cocuk-sahip-1
deinit sahip-2
deinit cocuk-sahip-2
deinit alt-sinif
deinit ust-sinif
deinit alt-sinif
deinit ust-sinif
ozellikteki-ornek: 2 degerlendirme, 2 kullanim -> her-kullanimda
ust-sinif-zinciri: 4 degerlendirme, 2 kullanim -> her-kullanimda
```

Çıktıda önce `deinit sahip-1`, ardından `deinit cocuk-sahip-1` görünür: dıştaki örneğin `deinit` gövdesi önce koşar, gövde biter bitmez özellikleri bırakılır ve içteki örneğin `deinit`'i bunu izler. Bu yüzden dıştaki `deinit` gövdesi içtekine hâlâ erişebilir. Alt sınıf zincirinde önce alt sınıfın, sonra üst sınıfın `deinit` gövdesi koşar. `ozellikteki-ornek` iki turda iki değerlendirme sayar, çünkü yalnız içteki `Session` onu çağırır. `ust-sinif-zinciri` ise tur başına iki `eval` gördüğü için iki turda dört değerlendirme sayar. İkisi de `her-kullanimda` der: değerlendirme sayısı kullanım sayısından fazla ya da ona eşit olabilir, kural yalnız bir kereden fazla koşup koşmadığına bakar. `deinit` açıkça çağrılamaz ve parametre almaz; yalnız sayaç sıfıra düştüğünde, bir kez, çalışma zamanı tarafından koşturulur.

## Üzerine Yazma Eskiyi Bırakır

`nil` ataması bırakmanın tek biçimi değildir. Bir `var` özelliğe yeni bir örnek atamak, özelliğin tuttuğu eski örneğin referansını da bırakır. Bu ölçüm bir `Slot` sınıfının `session` özelliğine ikinci bir `Session` atar ve atamanın iki yanında `evaluations` değerini yazdırır. Yeni örnek ayrı bir `Probe`'a bağlıdır; böylece sayılan `deinit` yalnız eski örneğe aittir.

```swift
// main.swift — ozelligin ustune yazma
final class Slot {
    var session: Session?

    init(_ session: Session?) {
        self.session = session
    }
}

let overwritten = Probe("ustune-yazma")
let spare = Probe("yedek")

for round in 1...2 {
    let slot = Slot(Session("eski-\(round)", owner: overwritten))
    print("yazmadan once \(overwritten.evaluations)")
    _ = overwritten.use { slot.session = Session("yeni-\(round)", owner: spare) }
    print("yazmadan sonra \(overwritten.evaluations)")
}

overwritten.report()
```

```
yazmadan once 0
deinit eski-1
yazmadan sonra 1
deinit yeni-1
yazmadan once 1
deinit eski-2
yazmadan sonra 2
deinit yeni-2
ustune-yazma: 2 degerlendirme, 2 kullanim -> her-kullanimda
```

Her turda `yazmadan once 0` ve `yazmadan sonra 1` satırları arasında `deinit eski-1` görünür: atama satırı yeni değeri yerleştirirken eski değerin son güçlü referansını bırakır ve eski örnek, atama bitmeden yok edilir. `deinit yeni-1` ise tur sonunda gelir, çünkü `slot` o noktada kapsamdan çıkar ve içindeki örneği de bırakır. Yani aynı özellik tur boyunca iki ayrı örneği sırayla tutmuş, iki ayrı `deinit` üretmiştir. `ustune-yazma` iki turda iki değerlendirme sayar ve `her-kullanimda` der. Kural değişmemiştir: `deinit` bir bırakma satırına bağlı değildir, sayacın sıfıra düşmesine bağlıdır. Üzerine yazma bu sayaçtan bir azaltır; `nil` ataması da, kapsam sonu da aynı işi yapar.

## Toplu Boşaltma

Bir dizinin tuttuğu örnekler tek tek değil, dizi boşaltılırken bırakılır. Bu ölçüm iki ayrı dizi kurar ve her birini `removeAll()` ile boşaltır. Soru, tek bir çağrının kaç `deinit` gövdesi koşturduğudur.

```swift
// main.swift — removeAll ile toplu birakma
let cleared = Probe("toplu-bosaltma")

for round in 1...2 {
    var batch = [
        Session("toplu-\(round)-a", owner: cleared),
        Session("toplu-\(round)-b", owner: cleared)
    ]
    print("bosaltmadan once \(cleared.evaluations)")
    _ = cleared.use { batch.removeAll() }
    print("bosaltmadan sonra \(cleared.evaluations), dizide \(batch.count)")
}

cleared.report()
```

```
bosaltmadan once 0
deinit toplu-1-a
deinit toplu-1-b
bosaltmadan sonra 2, dizide 0
bosaltmadan once 2
deinit toplu-2-a
deinit toplu-2-b
bosaltmadan sonra 4, dizide 0
toplu-bosaltma: 4 degerlendirme, 2 kullanim -> her-kullanimda
```

`removeAll()` çağrısı tek satırdır, ama içinde iki örnek bulunduğundan iki `deinit` koşar: `bosaltmadan once 0` ile `bosaltmadan sonra 2` arasında `deinit toplu-1-a` ve `deinit toplu-1-b` görünür. İkinci turda sayaç 2'den 4'e çıkar. Burada `Probe` iki kullanıma karşılık dört değerlendirme sayar ve yine `her-kullanimda` der; bir çağrının birden çok `deinit` koşturabilmesi `her-kullanimda` kuralıyla çelişmez, çünkü kural değerlendirme sayısına değil, bir kereden fazla koşup koşmadığına bakar. Dizinin bıraktığı her örnek kendi sayacına sahiptir. Biri başka bir değişkende de tutuluyor olsaydı, `removeAll()` yalnız dizinin payını bırakır ve o örneğin `deinit`'i sayaç sıfıra düşene kadar beklerdi; sınırlayıcı ölçüm bu durumu gösterir.

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

Yukarıdaki kural, `deinit`'in her bırakmada koştuğu izlenimini verebilir. Son ölçüm bunun yanlış olduğunu gösterir. Aynı örneği iki değişken tutar: `first` ve `second`. Önce `first` bırakılır, sonra `second`. `shared.evaluations` her adımdan sonra okunur.

```swift
// main.swift — ikinci referans ve ust duzey let
let shared = Probe("ikinci-referans")
let outlives = Probe("ust-duzey-let")

for round in 1...2 {
    var first: Session? = Session("ortak-\(round)", owner: shared)
    var second = first
    _ = shared.use { first = nil }
    print("birinci birakildi: \(shared.evaluations) deinit, ikinci \(second == nil ? "yok" : "var")")
    _ = shared.use { second = nil }
    print("ikinci birakildi: \(shared.evaluations) deinit")
}

let pinned = Session("ust-duzey", owner: outlives)
_ = outlives.use { pinned.name }
_ = outlives.use { pinned.name }

shared.report()
outlives.report()
```

```
birinci birakildi: 0 deinit, ikinci var
deinit ortak-1
ikinci birakildi: 1 deinit
birinci birakildi: 1 deinit, ikinci var
deinit ortak-2
ikinci birakildi: 2 deinit
ikinci-referans: 2 degerlendirme, 4 kullanim -> her-kullanimda
ust-duzey-let: 0 degerlendirme, 2 kullanim -> hic
```

İlk bırakmadan sonra `deinit` sayısı sıfırdır ve `second` hâlâ örneği tutar. `deinit ortak-1` satırı yalnız ikinci bırakmada görünür. İkinci turda aynı sıra yinelenir. Sayacın sıfıra düşmesi `deinit`'in koşma koşuludur; bırakma satırının kendisi koşul değildir. `ikinci-referans` `Probe`'u iki değerlendirme ve dört kullanım kaydeder ve `her-kullanimda` der, ama bunu tek başına söylemez: hangi bırakmanın `deinit`'i tetiklediği yalnız `print` sırasından ve araya konan `evaluations` okumalarından anlaşılır.

Son iki satır ikinci sınırı gösterir. Üst düzey `let` ile tutulan `pinned` iki kez kullanılır, ama `ust-duzey-let` `Probe`'u sıfır değerlendirme kaydeder ve `hic` der. Üst düzey bir `let` süreç sonuna kadar tutulur ve bu ölçümde süreç sonunda `deinit` koşmaz. `deinit`'in koşmaması bir hata değildir; referans sayısı hiç sıfıra düşmemiştir. Böyle bir örneğin `deinit` gövdesine güvenerek bir kaynağı kapatmak yanlış olur.

**BL1.** Her bırakma yolu için yalnızca bir örnek ölçüldü; kuralın başka bırakma yollarında da geçtiği bu derste gösterilmedi. Dört yolun seçilmesi tasarım tercihidir.

## Özet

- Sınıf örnekleri otomatik referans sayımıyla (ARC) yönetilir; son güçlü referans bırakıldığı anda `deinit` koşar.
- Kapsam sonu, `nil` ataması, diziden çıkarma ve döngü yinelemesi aynı kuralı izler: `deinit` bırakma noktasında koşar.
- İkinci bir güçlü referans `deinit`'i erteler; sayaç sıfıra düşmeden `deinit` koşmaz.
- Üst düzey bir `let`'in tuttuğu örnek süreç sonuna kadar bırakılmaz ve bu ölçümde `deinit` koşmaz (`hic`).
- Bu dersin anı: **her kullanımda**. Her yeni örneğin yok edilişi `deinit` gövdesini yeniden koşturur.

## Sonraki Adım

Bu derste sayaç sıfıra düşmek zorunda kaldı ve düştü. İki sınıf birbirini güçlü tutarsa sayaç hiçbir zaman sıfıra düşmez ve iki `deinit` de koşmaz. Sonraki ders, `weak` ve `unowned` ile bu döngüyü kırmayı ve `deinit` gövdesinin neden hiç değerlendirilmediğini ölçer.
