---
title: 'Objective-C ile Birlikte Çalışma'
source: 'https://academia.sh/tr/kurslar/ios-platformu/objective-c-ile-birlikte-calisma'
course: 'iOS Platformu ve Araçlar'
language: tr
updated: '2026-10-21T05:03:10+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Aynı seçiciye düşen iki Swift yönteminin reddedildiğini ölçer'
    - 'Köprüleme başlığı ile üretilen başlığın adlarının birleştiğini gösterir'
    - 'NS_SWIFT_NAME ile verilen adın üretilen adın önüne geçtiğini ölçer'
    - 'Dinamik dağıtımın modelin dışında kaldığını ayırır'
---

# Objective-C ile Birlikte Çalışma

Aynı Objective-C seçicisine düşen iki Swift yönteminin reddini, köprüleme başlığı ile üretilen başlığın adlarının birleşimini ve NS_SWIFT_NAME ile verilen adın önceliğini ölçer; kursu kapatır.

Eski projelerin büyük bölümü hâlâ **Objective-C** ile yazılıdır ve yeni kod çoğu zaman Swift'tir. İki dil aynı uygulamada yan yana yaşar. Bu mümkündür çünkü Swift, Objective-C'nin çalışma zamanına kendi bildirimlerinin bir bölümünü açabilir ve Objective-C başlıklarını içeri alabilir. Karşılığında bir sınır vardır: Objective-C yöntemleri **seçici (selector)** denen bir adla tanınır ve aynı sınıfta iki yöntem aynı seçiciyi taşıyamaz. Swift ise yöntemleri tür bilgisiyle de ayırabildiği için bu iki kuralın karşılaşması bir sonuç doğurur.

Ölçü ekseni son kez aynı: iki tanım buluşunca nasıl çözülüyor? Bu derste buluşan tanımlar seçici adları, başlıkların açtığı sınıf adları ve bir yöntemin iki farklı kaynaktan gelen Swift adlarıdır. Ders aynı zamanda kursun kapanışıdır.

## Sınıflandırıcı

```swift
// Meeting.swift — iki tanim bulusunca nasil cozuldugunu siniflandirir
struct Meeting {
    let label: String
    let first: Set<String>
    let second: Set<String>
    let result: Set<String>?

    init(_ label: String, first: Set<String>, second: Set<String>, result: Set<String>?) {
        self.label = label
        self.first = first
        self.second = second
        self.result = result
    }

    var resolution: String {
        if first.isEmpty || second.isEmpty
            || first.isSubset(of: second) || second.isSubset(of: first) {
            return "olcum-disi"
        }
        guard let result, !result.isEmpty else { return "ret" }
        if result == first.union(second) { return "birlesim" }
        if result == first.intersection(second) { return "kesisim" }
        if result == first || result == second { return "oncelik" }
        return "kural-disi"
    }

    static func list(_ values: Set<String>) -> String {
        values.isEmpty ? "bos" : values.sorted().joined(separator: ",")
    }

    func report() {
        let outcome = result.map(Meeting.list) ?? "yok"
        print("\(label): ilk \(Meeting.list(first)) | ikinci \(Meeting.list(second)) | sonuc \(outcome) -> \(resolution)")
    }
}

func summarize(_ meetings: [Meeting]) {
    for resolution in ["oncelik", "kesisim", "birlesim", "ret"] {
        let count = meetings.filter { $0.resolution == resolution }.count
        print("\(resolution): \(count)")
    }
}
```

## Aynı Seçici

Bir Swift sınıfı `NSObject`'ten türüyorsa ya da `@objc` ile işaretlenmişse yöntemleri Objective-C'ye görünür. Görünür her yöntem bir seçici kazanır. Seçici, yöntemin adından ve parametre etiketlerinden kurulur: `save(_:)` yöntemi `save:` seçicisine, `save(name:)` yöntemi `saveWithName:` seçicisine, parametresiz `reset()` yöntemi `reset` seçicisine dönüşür. Gerçek kural ilgi edatlarını ve birkaç özel durumu da gözetir; ders modeli bunları sadeleştirir ve yalnızca etiketsiz ile etiketli parametreyi ayırır.

Seçicide parametrenin tipi yoktur. Bu yüzden Swift'te meşru olan iki aşırı yükleme, Objective-C'de aynı seçiciye düşer.

```swift
@objc class Store: NSObject {
    @objc func save(_ value: Int) { }
    @objc func save(_ value: String) { }
}
```

Bu iki yöntem Swift'te birbirinden ayrılır, çünkü parametre tipleri farklıdır. Derleyici bu sınıfı yine de kabul etmez: ikisi de `save:` seçicisini ister. Derleyici reddini basmıyoruz; ders yalnızca model düzeyinde çarpışmayı sayar. Model her yöntemden seçici üretir, iki grubun seçicilerini karşılaştırır ve çarpışma varsa sınıfı hiçbir seçici açmadan bırakır. İkinci denemede çakışan yöntem `save(name:)` olarak etiketlenir ve aynı kural bu kez sonuç üretir.

```swift
// main.swift — ayni secici iki Swift yontemini reddettirir
struct SwiftMethod {
    let name: String
    let labels: [String]
}

func selector(for method: SwiftMethod) -> String {
    var text = method.name
    for (index, label) in method.labels.enumerated() {
        if index == 0 {
            text += label == "_" ? ":" : "With" + label.prefix(1).uppercased() + label.dropFirst() + ":"
        } else {
            text += (label == "_" ? "" : label) + ":"
        }
    }
    return text
}

func exposed(_ first: Set<String>, _ second: Set<String>) -> Set<String> {
    first.isDisjoint(with: second) ? first.union(second) : []
}

let intSave = SwiftMethod(name: "save", labels: ["_"])
let stringSave = SwiftMethod(name: "save", labels: ["_"])
let namedSave = SwiftMethod(name: "save", labels: ["name"])
let reset = SwiftMethod(name: "reset", labels: [])
let clear = SwiftMethod(name: "clear", labels: [])

let groupA: Set<String> = [selector(for: intSave), selector(for: reset)]
let groupB: Set<String> = [selector(for: stringSave), selector(for: clear)]
let groupC: Set<String> = [selector(for: namedSave), selector(for: clear)]

Meeting("same-selector", first: groupA, second: groupB, result: exposed(groupA, groupB)).report()
Meeting("labelled-overload", first: groupA, second: groupC, result: exposed(groupA, groupC)).report()
```

```
same-selector: ilk reset,save: | ikinci clear,save: | sonuc bos -> ret
labelled-overload: ilk reset,save: | ikinci clear,saveWithName: | sonuc clear,reset,save:,saveWithName: -> birlesim
```

İlk buluşma **ret**: iki grup da `save:` seçicisini istiyor, çarpışma var ve sınıf hiçbir seçici açmıyor, sonuç boş. İkinci buluşmada çakışan yöntemin etiketi `name` olunca seçici `saveWithName:` oldu, çarpışma kalmadı ve dört seçicinin hepsi açıldı: **birleşim**. Yani reddi doğuran Swift'in aşırı yüklemesi değil, Objective-C'nin türü görmeyen seçicisidir. Çözüm çoğu zaman yöntemlerden birine etiket vermektir.

**GO21.** Ölçüm seçiciyi ad ve etiketlerden kurdu. İlgi edatlarının özel kuralı, `@objc(name:)` ile seçicinin elle yazılması ve derleyicinin gerçek hata iletisi ölçülmedi.

## Köprüleme Başlığı

Objective-C kodu Swift'e **köprüleme başlığı (bridging header)** ile açılır. Başlık, Swift'in görmesi gereken Objective-C başlıklarını tek yerden içeri alır. Ters yön ise derleyicinin ürettiği bir başlıkla çözülür: Swift'te `@objc` ile açılmış sınıflar, `<ModülAdı>-Swift.h` adlı üretilmiş başlıkta Objective-C'ye görünür.

```objc
// Bridging-Header.h
#import "LegacyStore.h"
#import "LegacyLogger.h"
```

```objc
// Objective-C tarafı üretilmiş başlığı içeri alır
#import "App-Swift.h"
```

Karma bir modülde ikisi aynı anda geçerlidir. Köprüleme başlığı Swift'e `LegacyStore` ve `LegacyLogger` adlarını açar. Üretilmiş başlık Objective-C'ye `Router` ve `Formatter` adlarını açar. Modülün iki dilde birden kullanabildiği ad kümesi, her iki başlığın açtığı adların birleşimidir; hiçbir ad kendi başlığının dışında bir başlığın yerini almaz.

```swift
// main.swift — iki basligin actigi adlar birlesir
let bridgingHeader: Set<String> = ["LegacyStore", "LegacyLogger"]
let generatedHeader: Set<String> = ["Router", "Formatter"]
let moduleNames = bridgingHeader.union(generatedHeader)

Meeting(
    "mixed-module",
    first: bridgingHeader,
    second: generatedHeader,
    result: moduleNames
).report()
```

```
mixed-module: ilk LegacyLogger,LegacyStore | ikinci Formatter,Router | sonuc Formatter,LegacyLogger,LegacyStore,Router -> birlesim
```

Dört ad iki başlıktan geldi ve dördü de modülün kümesinde. İki başlığın adları kesişmediği için birleşim ile ayrık küme aynı sonucu verir; çözüm yine **birleşim**dir. Başlık değişmeden bir sınıf `@objc` işaretini kaybederse üretilmiş başlığın kümesi küçülür ve Objective-C tarafındaki kullanım derleme anında kırılır.

**GO22.** Ölçüm başlıkların açtığı adları küme olarak aldı. Üretilmiş başlıkta yer alan ama `@objc` ile işaretlenmediği için açılmayan üyeler, iki başlığın aynı adı farklı tanımlaması ve derleme sırası ölçülmedi.

## Verilen Ad ve Öncelik

Objective-C yöntemleri Swift'e içeri alınırken derleyici onlara kuralla bir Swift adı verir. Çoğu zaman ortaya çıkan ad Swift'in kendi üslubuna uymaz. Başlıktaki **NS_SWIFT_NAME** niteliği geliştiriciye Swift adını kendisi vermeyi sağlar.

```objc
// LegacyLoader.h
- (void)fetchItemsWithCompletion:(void (^)(NSArray *))completion
    NS_SWIFT_NAME(fetch(then:));
```

Burada iki ad vardır: kuralla üretilen `fetchItems(completion:)` ve geliştiricinin yazdığı `fetch(then:)`. Swift tarafında görünen yalnızca biridir. Verilen ad üretilen adın yerine geçer; ikisi birden görünmez. Model, bir yöntem için görünür adı verilen ad varsa ondan, yoksa üretilenden seçer.

```swift
// main.swift — NS_SWIFT_NAME ile verilen ad uretilen adin onune gecer
struct ImportedMethod {
    let generated: String
    let given: String?
    var visible: String { given ?? generated }
}

let loader = ImportedMethod(generated: "fetchItems(completion:)", given: "fetch(then:)")

Meeting(
    "swift-name",
    first: [loader.generated],
    second: [loader.given ?? loader.generated],
    result: [loader.visible]
).report()
```

```
swift-name: ilk fetchItems(completion:) | ikinci fetch(then:) | sonuc fetch(then:) -> oncelik
```

Verilen ad tek başına göründü: çözüm **öncelik**. Üretilen ad `fetchItems(completion:)` artık Swift tarafında yazılamaz; yalnız `fetch(then:)` geçerlidir. Bu kuralın bir bedeli vardır: Objective-C ve Swift kodu aynı yöntemi iki adla anar, bu yüzden adı ekibin iki dili okuyan herkesi hesaba katarak vermek gerekir.

**GO23.** Ölçüm tek bir yöntemin iki adını aldı. Verilen adın geçerli bir Swift adı olmaması, aynı sınıfta iki yöntemin aynı adı alması ve eski adın uyarıyla korunması ölçülmedi.

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

Son sınır dağıtımdır. Bir yöntem `@objc dynamic` ile işaretlendiğinde çağrı Swift'in doğrudan çağrısıyla değil, Objective-C çalışma zamanının ileti gönderimiyle çözülür. Aynı seçiciyi bir Objective-C sınıfı da bir alt sınıfta yeniden yazabileceği için, çağrının hangi gövdeye gittiği koşum anında belirlenir. Bu bir ad sorusu değil, bir gövde seçimi sorusudur ve bu kursun ölçüsü değildir. Çağrının gövdesini hangi tipin belirlediği önceki bir kursta (M08/K02) ölçülen eksendir.

Modele sormak için iki tarafın seçicisini yazalım: Swift gövdesi `refresh` der, Objective-C'deki yeniden yazım da `refresh` der.

```swift
// main.swift — dinamik dagitim ad kumesinde gorunmez
let swiftBody: Set<String> = ["refresh"]
let objcOverride: Set<String> = ["refresh"]

Meeting(
    "dynamic-dispatch",
    first: swiftBody,
    second: objcOverride,
    result: swiftBody
).report()
```

```
dynamic-dispatch: ilk refresh | ikinci refresh | sonuc refresh -> olcum-disi
```

İki taraf aynı seçiciyi taşıyor ve sonuç **ölçüm dışı**. Kümeler aynı olduğu için sınıflandırıcı bir buluşma görmedi; hangi gövdenin çalışacağı bu kümelerden okunamaz.

**GO24.** Ölçüm iki gövdenin seçici adını saydı. Hangi gövdenin çalıştığı, yeniden yazımın `super` çağırıp çağırmadığı ve `dynamic` olmayan çağrının doğrudan dağıtımı ölçülmedi.

## Özet

- Aynı Objective-C seçicisine düşen iki Swift yöntemi çarpışır; model bu durumda sınıfı reddeder ve etiket değişince çarpışma biter.
- Köprüleme başlığı Swift'e, üretilmiş başlık Objective-C'ye ad açar; karma modülün adları iki kümenin birleşimidir.
- `NS_SWIFT_NAME` ile verilen ad kuralla üretilen adın önüne geçer.
- Dinamik dağıtım ölçüm dışıdır: çağrının hangi gövdeye gittiği bir ad sorusu değil, bir gövde seçimi sorusudur.
- Bu dersin çözümü: **ret**.

## Kurs Kapanışı

Bu kursun on iki dersi tek bir soruyu yanıtladı: iki tanım buluşunca nasıl çözülüyor. Her ders bir buluşma kurdu, sonucu ölçtü ve dört addan biriyle söyledi. Tabloda ders, buluşma, çözüm ve o dersin sınırlayıcı ölçümü yan yana durur. İlk altı ders platformun yapısını, son altısı geliştirme ortamını kapsar.

| Ders | Buluşma | Çözüm | Sınırlayıcı ölçüm |
|---|---|---|---|
| Platform Katmanları | Platformun dört katmanı | çekirdeğin dördü (2/2/2/2) | İç içe iki tanım `olcum-disi` kalır |
| Çerçeveler ve Kütüphaneler | Çerçeve ve kütüphane adları | birleşim | Nitelenmiş ad ayrı bir ad sayılır |
| Alan Çerçeveleri | Alan izinleri | kesişim | İznin kapsamı okunmaz |
| Uygulama Yaşam Döngüsü | Yaşam döngüsü olayları | öncelik | Geçiş sırası ölçülmez |
| Arayüz Tasarım Kılavuzları | Kılavuz ve uygulama değerleri | öncelik | Kılavuz bir beklentidir, `kural-disi` kalır |
| Sürüm ve Uyumluluk | Sürüm aralıkları | kesişim | Asgari sürüm bir seçimdir |
| Geliştirme Ortamı | Aynı ayarın iki düzeyi | öncelik | Şema seçimi ölçüm dışıdır |
| Proje Dosya Yapısı | Şablon ve derleme anahtarları | birleşim | Anahtar sayılır, değer değil |
| Paket Yöneticisi | Sürüm kısıtları | kesişim | Seçilen sürüm değil, küme sayılır |
| Simülatör ve Aygıt | Gerekli ve sunulan yetenekler | ret | Başarım ölçülmez |
| Hata Ayıklama Temelleri | Kesme noktası kaynakları | birleşim | Adımlama sırası ölçülmez |
| Objective-C ile Birlikte Çalışma | Aynı seçiciye düşen yöntemler | ret | Dinamik dağıtım ölçüm dışıdır |

Açılış dersi dışındaki on bir dersin dağılımı şöyledir: üçü öncelik (Geliştirme Ortamı, Uygulama Yaşam Döngüsü, Arayüz Tasarım Kılavuzları), üçü kesişim (Alan Çerçeveleri, Sürüm ve Uyumluluk, Paket Yöneticisi), üçü birleşim (Çerçeveler ve Kütüphaneler, Proje Dosya Yapısı, Hata Ayıklama Temelleri), ikisi ret (Simülatör ve Aygıt, Objective-C ile Birlikte Çalışma). Bu sayım tablonun çözüm sütunundan çıkar. Kursun açılışındaki çekirdek ise sekiz buluşmayı 2/2/2/2 dağıtmıştı. İkisi aynı şey değildir: çekirdek sekiz buluşmayı, tablonun dağılımı açılış dışındaki on bir dersi sayar.

Kursun bıraktığı alışkanlık, iki tanımın karşılaştığı yeri önce adlandırmak, sonra çözümü ölçüme bırakmaktır. Platform, proje ve araç aynı soruyu farklı yüzlerden sorar; cevabın hangi kümeden çıktığını bilmek, yanlış bir kuralı sezgiyle uygulamaktan daha güvenilirdir. Sırada bu platformun üzerine kurulan arayüz var: M30/K03 bildirimsel arayüzü, görünüm ağacını ve durumu ele alır.
