← Back to list

iOS Swift Performans Master Serisi Part 2: “deinit” Neden Çalışmaz? Kapsamlı Senaryolar.

iOS “deinit” Neden Çalışmaz?

Abdulkadir Oruç · 2026-02-07 14:52 · 51 claps · 3.6 min read
#swift #swift-programming #deinit #weak-self #performance-management
Open on Medium ↗
Wiki topics: BIZ · Business Strategy 💻 · Programming 📱 · Mobile Development

“deinit” Neden Çalışmaz? Kapsamlı Senaryolar: iOS Swift Performans Master Serisi Part 2

1. “deinit” Nedir?

deinit, bir class instance’ı bellekte tamamen serbest bırakılmadan hemen önce çağrılan özel bir metottur.

class Example {
  deinit {
    print("Example deinit")
   }
}
  • deinit manuel çağrılmaz.
  • deinit ARC tarafından otomatik tetiklenir.
  • deinit çağrılıyorsa: Nesneye ait retain count = 0 olmuştur.

Eğer deinit çalışmıyorsa, bu bir hata değil; ARC’nin hâlâ o nesneye ihtiyaç duyduğunu düşündüğünün kanıtıdır.

2. “deinit" Neden Çalışmaz? (Temel Sebep)

Tek ve değişmez sebep:

Nesneye hâlâ en az bir strong reference vardır.

Tüm senaryolar bu cümlenin etrafında şekillenir.

deinit:Debug print değildir. “Çalıştı mı çalışmadı mı” kontrolü değildir.

deinit çalışmıyorsa:

  • Uygulama gereksiz bellek tutuyordur.
  • Performans düşer.
  • Scroll, animasyon ve network yavaşlar.

3. En Yaygın Senaryolar

3.1 Retain Cycle (Strong Reference Cycle)

Hatırlayalım: Retain Cycle, iki veya daha fazla nesnenin birbirini strong referansla tutması sonucu, ARC’nin hiçbirini serbest bırakamaması durumudur. Detaylı bilgiye Part 1'den erişebilirsiniz.

Örnek:

class A {
  var b: B?
}

class B {
  var a: A?
}

Burada:

  • A → B’yi tutar
  • B → A’yı tutar

Sonuç:

  • Her iki nesnenin retain count’u asla 0 olmaz.
  • deinit çağrılmaz.

Çözüm:

İlişkinin sahip olmayan tarafı weak veya unowned olmalıdır.

class B {
  weak var a: A?
}

3.2 ViewController — ViewModel İlişkisi (MVVM Mimarisi)

Problem:

class ViewModel {
  var viewController: MyVC
}
  • VC → ViewModel
  • ViewModel → VC

UI kapatılsa bile:

  • Nesneler birbirini tutmaya devam eder.

Doğru Model:

class ViewModel {
  weak var viewController: MyVC?
}

ViewModel, ViewController’ın sahibi değildir.

3.3 Closure’lar (En Sinsi Senaryo)

Closure’lar, tanımlandıkları scope’taki değişkenleri yakalayarak (capture) saklar.

Hatırlayalım: Class instance’ları strong olarak yakalanır.

Problemli Örnek:

class MyVC {

  func load() {

    service.fetch {
      self.updateUI()
    }
  }
}

Burada:

  • VC → service
  • service → closure
  • closure → self (VC)

Çözüm: Capture List

service.fetch { [weak self] in
  self?.updateUI()
}

3.4 Timer

Timer, belirli aralıklarla çalışan bir mekanizmadır. Bir kez başlatıldığında:

  • Kendi kendine durmaz.
  • Uygulamanın çalışma döngüsüne (RunLoop) eklenir
  • Süresi doldukça tekrar tekrar tetiklenir.

Timer, target’ını strong tutar.

timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
  self.tick()
}

Bu kod:

  • Her 1 saniyede bir çalışır.
  • Uygulama kapanana kadar devam eder.

Timer çalıştığı sürece:

  • VC serbest bırakılamaz.

Çözüm:

timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
    self?.tick()
}

Artık ekran kapandığında:

  • self artık yoktur (nil).
  • tick() çağrılmaz.
  • Uygulama çökmez.
  • Bellek sızıntısı olmaz.

Bu yüzden:

“Her şey çalışıyor gibi” görünür.

Ama perde arkasında ne oluyor?

  • Timer hâlâ çalışıyor.
  • Her saniye tetikleniyor.
  • Closure çağrılıyor.
  • İçeride hemen çıkılıyor.

Yani:

  • Gereksiz işlem yapılıyor.
  • Küçük de olsa CPU ve enerji harcanıyor.

Tek bir timer için bu fark edilmez. Ama: Birçok ekranda birçok timer varsa bu durum birikerek sorun hâline gelir.

**invalidate() ne yapar?**

invalidate() timer’a şunu söyler:

“Artık görevini tamamladın, durabilirsin.”

Teknik olarak:

  • Timer RunLoop’tan çıkarılır.
  • Bir daha tetiklenmez.
  • Tamamen etkisiz hâle gelir.
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        timer?.invalidate()
        timer = nil
    }

Bu çağrıdan sonra:

  • Timer artık çalışmaz.
  • Tekrar başlatılmadan geri gelmez.

3.5 Singleton’lar

Singleton’lar uygulama boyunca yaşayan nesnelerdir.

Örnek:

class Manager {
  static let shared = Manager()
}

Eğer bu singleton bir ViewController’ı strong referansla tutarsa:

class Manager {
    static let shared = Manager()
    var delegate: SomeViewController?
}

ve bir yerde:

Manager.shared.delegate = self

olursa:

  • Singleton → VC (strong).
  • Singleton hiç ölmez.
  • VC de hiçbir zaman serbest bırakılamaz.

Sonuç:

  • deinit çalışmaz.
  • Memory leak oluşur.
  • Ekran kapansa bile VC bellekte kalır.

Çözüm:

Singleton UI nesnesi tutmamalı.

Singleton’ın sorumluluğu:

  • Veri
  • İş mantığı
  • Servis yönetimi

Ekran, View, ViewController değil.

Eğer gerçekten bir VC’ye işaret etmesi gerekiyorsa:

class Manager {
    static let shared = Manager()
    weak var delegate: SomeViewController?
}

Bu sayede:

  • VC kapanınca nil olur.
  • Singleton hayatta kalır.
  • Leak oluşmaz.

3.6 Combine / RxSwift

Combine’da Publisher ve Subscriber arasındaki bağlantı, bir Subscription üzerinden kurulur.

Bu subscription aktif olduğu sürece akış devam eder.

Eğer bir Publisher’a yapılan subscription iptal edilmezse:

publisher
    .sink { value in
        self.handle(value)
    }
  • Publisher → Subscriber (strong).
  • Subscriber → ViewController (strong).
  • Subscription aktif kaldığı sürece zincir kopmaz.

Özellikle Subject veya hiç complete etmeyen publisher’larda:

  • Subscription kendiliğinden bitmez.
  • ViewController serbest bırakılamaz.

Çözüm:

Subscription’lar mutlaka ViewController yaşam döngüsüne bağlanmalıdır.

publisher
    .sink { [weak self] value in
        self?.handle(value)
    }
    .store(in: &cancellables)

Bu sayede:

  • weak self ile retain cycle kırılır.
  • cancellables deinit olunca tüm subscription’lar otomatik olarak cancel() edilir.
  • ViewController serbest bırakılabilir.

3.7 Async / Await & Task

Task {
  await self.load()
}

Task:

  • self’i strong tutar.

Çözüm:

Task { [weak self] in
  await self?.load()
}

veya:

Task.cancel()

4. Altın Kurallar

4.1 “Bunun Sahibi Kim?” Sorusu

Her class için sorulması gereken en kritik soru budur:

Bu nesnenin yaşam süresini kim kontrol ediyor?

Sahiplik (Ownership) Ne Demektir?

Bir nesnenin sahibi, onun:

  • Ne zaman oluşturulacağına
  • Ne zaman yok edileceğine

dolaylı veya doğrudan karar veren yapıdır.

ARC açısından sahiplik şudur:

  • Sahip olan → strong referans tutar.
  • Sahip olmayan → weak veya unowned tutar.

Yanlış Sahiplik Örneği

class ViewModel {
  var viewController: MyViewController
}

Burada ViewModel şunu iddia eder:

“Ben ViewController’ın sahibiyim”

Bu mantıksal olarak yanlıştır, çünkü:

  • ViewController ekrana gelir.
  • ViewController gider.
  • ViewModel onunla birlikte ölmelidir.

Doğru Sahiplik Modeli

class ViewModel {
  weak var viewController: MyViewController?
}

Altın Kural:

UI katmanı genellikle sahip olunan taraftır, sahip olan değil.

4.2 Closure Yazarken Refleks: [weak self]

  • Closure’ın ne kadar yaşayacağını bilemezsin.
  • Network gecikir.
  • Async işlem uzar.
  • Task askıda kalır.

Doğru Refleks

service.fetch { [weak self] in
  self?.updateUI()
}

4.3 "deinit" Görmüyorsan Ne Yapmalısın?

deinit çalışmıyorsa:

  • Tahmin yürütme.
  • Koddan çıkarmaya çalışma.

Doğru Araç: Memory Graph Debugger

Memory Graph Debugger sana şunu gösterir:

  • Hangi nesne
  • Hangi nesneyi
  • Hangi referans türüyle tutuyor

Nasıl Düşünmelisin?

  1. ViewController kapatılır.
  2. deinit beklenir

Gelmiyorsa:

  • Kim tutuyor?
  • Strong mu?
  • Gereksiz mi?

*deinit gelmiyorsa sorun orada değil, onu tutan yerdedir.*

Bu bölümle birlikte iOS Performans iyileştirme anlamında en temel ve önemli konuları öğrendik, temel senaryoları önleyebilir hale geldik. Serinin diğer bölümlerinde daha üst seviyelere çıkarak bütün kapsamı tamamlayacağız. 🚀


메타데이터
post_id
c5b5a3fdc467
slug
ios-swift-performans-master-serisi-part-2-deinit-neden-çalışmaz-kapsamlı-senaryolar-c5b5a3fdc467
url
https://medium.com/@kadiroruc/ios-swift-performans-master-serisi-part-2-deinit-neden-%C3%A7al%C4%B1%C5%9Fmaz-kapsaml%C4%B1-senaryolar-c5b5a3fdc467
canonical_url
https://medium.com/@kadiroruc/ios-swift-performans-master-serisi-part-2-deinit-neden-%C3%A7al%C4%B1%C5%9Fmaz-kapsaml%C4%B1-senaryolar-c5b5a3fdc467
author_url
https://medium.com/@kadiroruc
status
ok
fetched_at
2026-07-13 06:23:13