---
title: 'Yapılar ve Sınıflar'
source: 'https://academia.sh/tr/kurslar/swift/yapilar-ve-siniflar'
course: 'Swift Dili'
language: tr
updated: '2026-10-21T05:03:13+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Yapı atamasının bağımsız bir kopya, sınıf atamasının paylaşılan bir nesne verdiğini ölçer'
    - 'Varsayılan değerin yalnızca verilmediğinde ve her örnekte ayrı değerlendirildiğini gösterir'
    - 'Yazarken kopyalamada kopyanın atamada değil ilk değişiklikte oluştuğunu ölçer'
    - 'Tek sahipli ve sınıf içinde paylaşılan değerde kopyanın hiç oluşmadığını gösterir'
---

# Yapılar ve Sınıflar

Yapıların atamada kopyalanmasının, sınıfların paylaşılmasının, varsayılan değerin ne zaman kurulduğunun ve kopyanın ilk değişiklikte oluşmasının ölçümü.

Önceki ders kutuyu açmanın yollarını ölçtü ve her yolun ifadeyi ne zaman değerlendirdiğini sıraladı. Açılan değer bir `Int` ya da bir `String` olabilir, ama programın asıl verisi çoğu zaman birkaç alanı bir arada tutan bir tiptir: bir nokta, bir sipariş, bir belge. Swift'te böyle tiplerin iki temel biçimi vardır (numaralandırmalar ve aktörler ayrı derslerin konusu). **Yapı (structure)** bir **değer tipidir**: atandığında içeriği kopyalanır. **Sınıf (class)** bir **referans tipidir**: atandığında aynı nesneye ikinci bir ad verilir.

Bu fark çoğu kitapta "kim neyi görüyor" sorusuyla anlatılır: bir adın değişikliğini öbür ad görüyor mu? Bu ders başka bir soruyu sorar: kopya ne zaman oluşuyor? Atamanın kendisi bir kopya mı üretir, yoksa kopya yalnızca ilk değişiklikte mi ortaya çıkar? Kursun ölçü ekseni bu soruyu dört ana ayırır: hemen, ilk kullanımda, her kullanımda, hiç. `Probe` sınıfı aşağıda olduğu gibi verilir.

## Çekirdek

Her ders aynı çekirdeği kullanır. `Probe` bir ifadenin kaç kez değerlendirildiğini (`eval`) ve kaç kez kullanıldığını (`use`) sayar; `moment` özelliği bu iki sayıdan anı çıkarır. Açılış dersindeki bağlayıcı ölçümde sekiz ifadenin dağılımı 2/1/3/2 idi: ikisi hemen, biri ilk kullanımda, üçü her kullanımda, ikisi hiç. Bu derste yalnız kendi kesitini ölçeriz.

```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)")
    }
}
```

Aşağıdaki ilk ölçümler üç tip kullanır. `Point` iki tamsayı tutan bir yapıdır, `Counter` tek bir sayaç tutan bir sınıftır. `Order` varsayılan değerli bir alana sahip bir yapıdır; varsayılan değer bir işlev çağrısıdır ve işlev çalıştığında bir satır yazdırır. Bu bloğun çıktısı yoktur, çünkü yalnızca tipleri tanımlar.

```swift
// Types.swift — bir yapi, bir sinif ve varsayilan degerli bir yapi
struct Point {
    var x: Int
    var y: Int
}

final class Counter {
    var value = 0
}

func makeNote() -> String {
    print("varsayilan deger kuruldu")
    return "yok"
}

struct Order {
    var id: Int
    var note = makeNote()
}
```

## Atama: Kopya mı, Paylaşım mı

Aynı iki satırı bir yapıyla ve bir sınıfla yazalım. Yapıda `var second = first` ardından `second.x = 10` yazıldığında `first` değişmez. Sınıfta `let right = left` ardından `right.value = 5` yazıldığında iki ad aynı nesneye bağlıdır ve her ikisi de `5` görür.

```swift
// main.swift — yapi atamada kopyalanir, sinif paylasilir
let first = Point(x: 1, y: 2)
var second = first
second.x = 10
print(first.x, second.x)

let left = Counter()
let right = left
right.value = 5
print(left.value, right.value)
```

```
1 10
5 5
```

Birinci satır yapıyı gösterir: `first.x` `1` kaldı, `second.x` `10` oldu. Atama bağımsız bir kopya verdi. İkinci satır sınıfı gösterir: `left.value` ve `right.value` ikisi de `5`'tir, çünkü tek bir `Counter` nesnesi vardır ve iki ad ona bağlıdır. Dikkat edin ki `right` bir `let` sabitidir ve yine de nesnenin içindeki `value` değişebildi: `let` adın başka bir nesneye bağlanmasını yasaklar, bağlı nesnenin içeriğini yasaklamaz. Yapıda ise `let` bütün değerin değişmezliği anlamına gelir: değişmez bir yapının alanı, alan `var` olarak tanımlanmış olsa bile atanamaz.

Çıktı iki tipi birbirinden ayırır ama kopyanın ne zaman oluştuğunu söylemez. Yapı için "atamada kopyalanır" cümlesi ders kitaplarında bir model olarak vardır; ölçtüğümüz şey ise gözlenebilir davranıştır: değişiklikten sonra iki değer bağımsızdır. Kopyanın fiziksel olarak atamada mı yoksa sonradan mı oluştuğu aşağıda ölçülecek.

**TS9.** Bu ölçüm iki tamsayı alanlı bir yapı ve tek alanlı bir sınıf için. Alanların başka bir sınıfa referans tuttuğu yapılar ve yapı içindeki sınıf alanlarının kopyalanması bu ölçümde yok.

## İşleve Geçirme

Atama değer ile referans ayrımının yalnız bir yüzüdür; aynı ayrım bir işleve argüman verirken de yaşanır. Bir işlev yapıyı parametre olarak aldığında kendi kopyasıyla çalışır: içeride yapılan değişiklik, çağıran tarafın değerine ulaşmaz. Sınıf parametresinde ise işlev ile çağıran aynı nesneye bakar. Aşağıdaki ölçümde `moved` yapının bir kopyasını değiştirip döndürür, `bump` ise sayacı yerinde değiştirir.

```swift
// main.swift — isleve gecirilen yapi kopyalanir, sinif paylasilir
func moved(_ point: Point) -> Point {
    var copy = point
    copy.x += 100
    return copy
}

func bump(_ counter: Counter) {
    counter.value += 100
}

let origin = Point(x: 1, y: 2)
let shifted = moved(origin)
print(origin.x, shifted.x)

let ticker = Counter()
bump(ticker)
print(ticker.value)
```

```
1 101
100
```

Birinci satırda `origin.x` `1` olarak kaldı, `shifted.x` ise `101` oldu: `moved` içindeki `copy` ayrı bir değerdi ve değişiklik yalnızca ona yazıldı. İkinci satırda `ticker.value` `100` oldu, çünkü `bump` aynı `Counter` nesnesini değiştirdi ve işlevin döndürdüğü bir şey yok. Bu yüzden parametresi yapı olan bir işlevin imzası, yapı yalnız değer tutuyorsa ve parametre `inout` değilse, okuyana "bu işlev çağırdığım değeri değiştirmez" der. Parametresi sınıf olan bir işlevin imzası böyle bir güvence vermez; işlevin gövdesine bakmak gerekir.

Bu ayrımın pratik sonucu, hata ayıklamada görünür. Bir yapının değeri beklenmedik biçimde değiştiyse, değişiklik o değerin kendi kapsamında yapılmıştır; bir sınıf nesnesi beklenmedik biçimde değiştiyse, nesneye ulaşabilen her yer şüphelidir. İşlev imzaları arasında değer tipi kullanmak şüpheli alanı daraltır.

**TS10.** Bu ölçüm bir yapı ve bir sınıf parametresi için. `inout` parametre ile geçirme ve kapanışın yakaladığı yapı bu ölçümde yok.

## Varsayılan Değer: Her Örnekte Bir Kez

`Order` yapısının `note` alanı `makeNote()` işlevinin sonucuyla başlar. Bu varsayılan değer bir kez kurulup bütün örnekler arasında paylaşılmaz; her `Order` örneği kendi varsayılan değerini oluşturur. Üstelik değer, çağıran taraf alanı kendisi vermişse hiç hesaplanmaz. Üç siparişle ölçelim: ikisi varsayılan notla, biri açık bir notla.

```swift
// main.swift — varsayilan deger her ornekte, ama yalniz verilmediyse degerlendirilir
let o1 = Order(id: 1)
let o2 = Order(id: 2)
let o3 = Order(id: 3, note: "acele")
print(o1.note, o2.note, o3.note)
```

```
varsayilan deger kuruldu
varsayilan deger kuruldu
yok yok acele
```

`makeNote()` iki kez çalıştı, üç siparişin ikisi için. Notu açıkça veren üçüncü sipariş için işlev hiç çağrılmadı. Çalıştığı iki yer de yazdırma satırından önce görünür; yani varsayılan değer, örnek kurulurken, çağıran satırda hesaplandı.

Bir sonuç çıkar: varsayılan değer olarak yazılan her ifade örnek sayısı kadar değerlendirilir, verilen değer sayısı kadar eksik. Değerlendirmesi pahalı bir ifade varsayılan değer olarak yazılırsa, bu maliyet her örnekte ödenir. Özellikler dersinde `lazy` ile bu maliyetin ertelenmesi ölçülecek.

**TS11.** Bu ölçüm üç örnekle ve bir varsayılan değerli alanla yapıldı. Birden çok varsayılan değerli alanın değerlendirme sırası ve sınıflarda aynı durum ayrıca ölçülmedi.

## Yazarken Kopyalama

Büyük bir değer tipi atandığında gerçekten tamamını kopyalamak israf olurdu. Standart kitaplığın bazı tipleri bu yüzden **yazarken kopyalama (copy-on-write)** denen bir teknik kullanır: atama yalnızca bir depoya ikinci bir referans ekler; kopya ancak ortak depoyu değiştirmek gerektiğinde, ilk değişiklikte oluşur. Aynı tekniği kendi tipimizde elle kurabiliriz. `Document` yapısı metni bir `Storage` sınıfında tutar. `append` önce depoya tek başına mı sahip olduğumuzu `isKnownUniquelyReferenced` ile sorar; değilse depoyu kopyalar ve kopyalama anını `onCopy` kapanışıyla bildirir.

```swift
// Document.swift — sinif kutulu, yazarken kopyalayan yapi
final class Storage {
    var text: String

    init(text: String) {
        self.text = text
    }
}

struct Document {
    private var storage: Storage
    private let onCopy: () -> Void

    init(text: String, onCopy: @escaping () -> Void) {
        storage = Storage(text: text)
        self.onCopy = onCopy
    }

    var text: String {
        storage.text
    }

    mutating func append(_ more: String) {
        if !isKnownUniquelyReferenced(&storage) {
            onCopy()
            storage = Storage(text: storage.text)
        }
        storage.text += more
    }
}

final class Holder {
    var document: Document

    init(_ document: Document) {
        self.document = document
    }
}
```

Koda yakından bakalım. `storage` alanı `private` olduğu için dışarıdan görünmez; dışarıya yalnızca salt okunur `text` özelliği açılır. Değişiklik yalnız `mutating` olarak işaretli `append` içinden geçer ve kopyalama kararı da yalnızca orada verilir. Bu daraltma önemlidir: kopyalama kuralı tek bir yerde durduğu için, tipin başka hiçbir yöntemi depoyu paylaşılan halde değiştiremez. `onCopy` kapanışı ise ölçüm içindir; üretim kodunda böyle bir bildirim bulunmaz, ama burada kopyanın tam olarak hangi çağrıda oluştuğunu saymamızı sağlar. `Holder` sınıfı ise son ölçümde kullanılacak: bir `Document` değerini bir sınıf nesnesinin alanı yapar.

Bu bloğun çıktısı yoktur; yalnızca `Document` ve onu bir sınıfa saran `Holder` tanımlıdır. Şimdi `duplicate = original` ataması yapılıp ikisi de değiştirilince kopyanın tam olarak ne zaman oluştuğunu ölçelim. `onCopy` kapanışı `cow.eval` ile sarılıdır; iki kez `append` çağrılır.

```swift
// main.swift — kopya atamada degil, ilk degisiklikte olusur
let cow = Probe("yazarken-kopyalama")
let original = Document(text: "ab", onCopy: { _ = cow.eval(()) })
var duplicate = original

_ = cow.use { duplicate.append("c") }
_ = cow.use { duplicate.append("d") }
cow.report()
print(original.text, duplicate.text)
```

```
yazarken-kopyalama: 1 degerlendirme, 2 kullanim -> ilk-kullanimda
ab abcd
```

Atamanın kendisi kopya üretmedi: değerlendirme sayısı bir ve an **ilk kullanımda**. İlk `append` depoyu başka bir değerle paylaşıyordu, bu yüzden kopya o anda oluştu. İkinci `append` kopyalanan depoya tek başına sahipti, kopya gerekmedi. Son satır sonucu doğrular: `original` hâlâ `ab`, `duplicate` ise `abcd`. Ortada iki değer var ama yalnızca bir kopyalama yaşandı ve o da atamada değil, ilk değişiklikte.

Sayıların anlamını da yazalım. Bir değerlendirme, kopyanın bir kez oluştuğunu söyler; iki kullanım, iki `append` çağrısı yapıldığını söyler. Değerlendirme sayısı kullanım sayısına eşit olsaydı her değişiklik kopya doğururdu ve an **her kullanımda** olurdu. Sıfır olsaydı hiçbir değişiklik kopya gerektirmezdi ve an **hiç** olurdu. Ölçülen bir, ikinin altındadır ve ilk kullanımda oluşmuştur; bu üç sayı birlikte anı belirler.

Bu ölçüm başta sorduğumuz soruyu yanıtlar. Depoyu paylaşan `Document` gibi bir değer tipinde kopya atamadan sonra, ilk yazma sırasında oluşur. Okuyan taraf için bir fark yoktur; kopyanın bedeli, ilk yazan tarafa düşer. Bu yüzden değer tipi ile referans tipi arasındaki seçim yalnız anlamsal bir tercih olarak değil, bedelin ne zaman ödeneceği olarak da okunabilir.

**TS12.** Bu ölçüm yalnızca elle kurduğumuz `Document` tipi için; standart kitaplığın dizi, sözlük ve dize tiplerinin kendi yazarken kopyalamaları bu derste ölçülmedi.

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

Yazarken kopyalama için kurduğumuz kural şu: kopya ilk değişiklikte oluşur. Kuralın bir koşulu vardır, depo başka bir sahiple paylaşılıyor olmalı. İki durumda bu koşul oluşmaz. Birincisinde `solo` belgesine kimse ortak olmamıştır; ikincisinde belge bir sınıfın içindedir ve iki ad aynı sınıf nesnesine bağlıdır, yani depoyu paylaşan ikinci bir `Document` değeri yoktur. Her ikisinde de iki kez `append` çağrılır.

```swift
// main.swift — tek sahipli ya da sinif icinde paylasilan belge kopyalanmaz
let unique = Probe("tek-sahipli")
var solo = Document(text: "ab", onCopy: { _ = unique.eval(()) })
_ = unique.use { solo.append("c") }
_ = unique.use { solo.append("d") }

let shared = Probe("sinif-paylasimi")
let holder = Holder(Document(text: "ab", onCopy: { _ = shared.eval(()) }))
let alias = holder
_ = shared.use { holder.document.append("c") }
_ = shared.use { alias.document.append("d") }

unique.report()
shared.report()
print(solo.text, holder.document.text, alias.document.text)
```

```
tek-sahipli: 0 degerlendirme, 2 kullanim -> hic
sinif-paylasimi: 0 degerlendirme, 2 kullanim -> hic
abcd abcd abcd
```

İki durumda da `onCopy` hiç çağrılmadı: an **hiç**. Tek sahipli belge ilk değişiklikte bile kopyalanmadı, çünkü paylaşılacak bir ikinci sahip yoktu. Sınıf içindeki belge de kopyalanmadı: `holder` ve `alias` aynı `Holder` nesnesine bağlı olduğundan, bir ad üzerinden yapılan ekleme ötekinde de görünür ve `Document` değerinin ikinci bir kopyası hiç oluşmaz. Son satır bu paylaşımı doğrular: üç ad da `abcd` yazar.

Bu sınır dersin kuralını daraltır. "Değer tipi atamada kopyalanır" cümlesi ve onu tamamlayan "kopya ilk değişiklikte oluşur" cümlesi, yalnızca depoyu paylaşan iki ayrı değer varsa geçerlidir. Değer tipi bir sınıfın alanıysa sınıfın referans anlamı baskın çıkar: kopya oluşmaz, çünkü sınıf nesnesi zaten tektir.

**TS13.** Bu ölçüm tek bir sınıf nesnesi ve iki ad için. Sınıf nesnesinin kendisi `Document` alanıyla birlikte başka bir değere atandığında ya da iki farklı `Holder` nesnesinin aynı belgeyi taşıdığı durum ölçülmedi.

## Özet

- Yapı atamada bağımsız bir kopya verir; sınıf atamasında iki ad aynı nesneye bağlanır.
- `let` ile tanımlanan sınıf adı nesneyi değişmez yapmaz; `let` ile tanımlanan yapı bütün değeri değişmez yapar.
- Varsayılan değer her örnekte bir kez değerlendirilir ve çağıran alanı verdiyse hiç değerlendirilmez.
- Yazarken kopyalamada kopya atamada değil ilk değişiklikte, depo paylaşılıyorsa oluşur.
- Tek sahipli ya da sınıf içinde paylaşılan değerde kopya hiç oluşmaz.
- Bu dersin anı: **ilk kullanımda**. Yazarken kopyalanan belgede kopya ilk değişiklikte oluşur.

## Sonraki Adım

Bu derste bir tipin değer mi referans mı olduğu ve kopyanın ne zaman oluştuğu ölçüldü. Bazı tiplerin bir alan listesi değil, birkaç ayrı durumdan birinde olması gerekir: bir ölçüm ya derece cinsindendir ya da bir etikettir. Bir sonraki ders bu durumları ve her durumla birlikte taşınan değerleri anlatan numaralandırmaları ölçer.
