Swift’te Bellek Yönetimi: Pratik Örneklerle İncelikler
Uygulama geliştirme sürecinde karşılaşılan en zorlu sorunlardan biri, memory leak’lerdir. Kişisel projelerimde de deneyimlediğim gibi, özellikle reaktif programlama kütüphaneleri kullanırken abonelik(subscription) yönetimi ve güçlü referansların kontrolsüz kullanımı, beklenmeyen bellek sızıntılarına(leaks) neden olabilir. Örneğin, RxSwift aboneliklerini DisposeBag
kullanmadan yönetmek, aboneliklerin zamanında serbest bırakılmamasına ve uygulamanın performansının düşmesine sebep olabilir.
Başka bir örnek ise, delegate’lerin güçlü referanslarla(strong reference) tutulması sonucunda oluşan döngüsel referanslardır(retain cycle). Bu durum, nesnelerin beklenmeyen şekilde bellekte kalmasına ve uygulamanın kaynaklarını gereksiz yere tüketmesine yol açabilir. Bu tür hataların önlenmesi için, doğru programlama pratiklerini uygulamak ve uygun araçları kullanmak önemlidir.
Bu makalede, kendi projelerimden edindiğim deneyimleri ve bu tür bellek yönetimi hatalarını nasıl önleyebileceğimizden bahsedeceğim. Bu sayede, benzer sorunlarla karşılaşan diğer geliştiricilere yardımcı olmayı ve memory leaks konusunda daha kararlı uygulamaların geliştirilmesine katkıda bulunmayı amaçlıyorum.
Örnek #1
Açıklama:
Bu örnekteki ilk memory leak sebebi FavoritesHelper
sınıfının içindeki “self” referansının retain cycle’a neden olmasıdır. Bu retain cycle’ı kırmak için “weak” veya “unowned” self kullanabiliriz. Bu sayede FavoritesHelper
nesnesinin “subscribe” içinde güçlü bir referansla tutulmasını engellemiş oluruz.
İkinci memory leak sebebi ise “DisposeBag” kullanılmadığı için oluşmaktadır. RxSwift
ile çalışırken, aboneliklerin (subscriptions) yönetilmesi ve doğru bir şekilde serbest bırakılması önemlidir.“DisposeBag”, abonelikleri yönetmek ve belirli bir yaşam döngüsü boyunca aboneliklerin serbest bırakılmasını sağlamak için kullanılır. Eğer “DisposeBag” kullanılmazsa, abonelikler serbest bırakılmaz ve memory leak oluşur.
Sonuç:
Örnek #2
Açıklama:
Bu örnekte birden fazla sayıda memory leak oluşturacak “strong reference” property bulunuyor. Bu property’ler retain cycle oluşturmaktadır.
- Strong Reference:
SimpleJokeCell
içerisinde bulunan “viewModel” referansını “strong reference” olarak tutulması memory leak’e sebep olmaktadır. Bu leak’i engellemek için “viewModel” referansını “weak reference” olarak kullanabiliriz. - Closure Retain Cycle:
SimpleJokeCell
içerisinde bulunan “cellForRowAt” closure’ı, “self” referansını “strong” olarak tutar. Bu, closure’ınSimpleJokeCell
nesnesini serbest bırakmasını engeller ve retain cycle oluşturur. Bu leak’i closure içerinde “self”i “weak reference” olarak kullanarak engelleyebiliriz. - Delegate Retain Cycle:
SimpleJokeCell
’in,SimpleJokeTableViewCell
’in “delegate” i olarak atanması retain cycle oluşturabilir.SimpleJokeTableViewCell
'in “delegate” i güçlü bir referans olarak tutuluyorsa veSimpleJokeCell
deSimpleJokeTableViewCell
'i güçlü bir referansla tutuyorsa, retain cycle oluşur. Bu leak'iSimpleJokeTableViewCell
’in “delegate” property’sini “weak reference” yaparak engelleyebiliriz.
Sonuç:
Örnek #3
Açıklama:
“NotificationCenter” observer'ları “strong reference” tutar. İhtiyacımız bittiğinde observer'ları kaldırmazsak, “strong reference” oluşur ve EditMessageViewController
serbest bırakılamaz. Bu leak’i engellemek için “viewDidDisappear” içerisinde observer’ları kaldırabiliriz.
Sonuç:
Bu makalede paylaştığım deneyimlerimin, sizin projelerinizde de faydalı olacağını umuyorum. Yazılım geliştirme sürecinde hatalardan öğrenmek ve bu hataları gelecekteki projelerimizde önlemek, her zaman önemli bir adımdır. Doğru pratikleri benimsemek ve kodunuzu düzenli olarak gözden geçirmek, hem uygulamanızın kalitesini artırır hem de geliştirici olarak sizin kendinizi geliştirmenize yardımcı olur.