Swift'te Otomatik Bellek Yönetimi (ARC) nasıl çalışır?
sobes.tech yapay zeka
AI'dan gelen yanıt
Swift'te Otomatik Referans Sayacı (ARC), uygulamalarınızın bellek kullanımını izler ve yönetir. Artık ihtiyaç duyulmayan sınıf örnekleri tarafından kullanılan belleği otomatik olarak serbest bırakır, böylece bellek sızıntılarını önler.
Yeni bir sınıf örneği oluşturulduğunda, ARC bu örnek hakkında bilgi saklamak için bir bellek bloğu ayırır. Artık gerekmediğinde, ARC bu belleği serbest bırakır ve başka amaçlar için kullanılabilir hale getirir.
ARC, her sınıf örneğine güçlü referansların (strong references) sayısını sayarak çalışır. Güçlü bir referans, örneği bellekte tutar. Güçlü referansların sayısı sıfıra düştüğünde, ARC ilgili belleği serbest bırakır.
Swift'te ARC'yi etkileyen üç referans türü vardır:
- Güçlü Referanslar (Strong References): Referans sayacını artırır.
- Zayıf Referanslar (Weak References): Referans sayacını artırmaz. Güçlü referans döngülerini önlemek için kullanılır, iki sınıf örneği birbirine güçlü referanslar tutarken. Zayıf referans otomatik olarak
nilolur örnek yok edildiğinde. - Unowned Referanslar (Unowned References): Ayrıca referans sayacını artırmaz. Bir örneğin, diğer örnek var olduğu sürece var olacağından emin olduğunuz durumlar için kullanılır. Opsiyonel olamaz (
nil). Bu referansa erişmeye çalışmak çalışma zamanında hata oluşturur.
Güçlü referans döngüsüne örnek:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) başlatılıyor")
}
deinit {
print("\(name) sonlandırılıyor")
}
}
class Apartment {
let unit: String
var tenant: Person?
init(unit: String) {
self.unit = unit
print("Daire \(unit) başlatılıyor")
}
deinit {
print("Daire \(unit) sonlandırılıyor")
}
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil // Person sonlandırılmıyor
unit4A = nil // Apartment sonlandırılmıyor
Bu döngüyü çözmek için, zayıf veya unowned referanslar kullanın. Bu durumda, Apartment içindeki tenant zayıf bir referans olmalı:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) başlatılıyor")
}
deinit {
print("\(name) sonlandırılıyor")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Zayıf referans kullanımı
init(unit: String) {
self.unit = unit
print("Daire \(unit) başlatılıyor")
}
deinit {
print("Daire \(unit) sonlandırılıyor")
}
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john?.apartment = unit4A
unit4A?.tenant = john
john = nil // Person sonlandırılıyor
unit4A = nil // Apartment sonlandırılıyor
Nesneler arasındaki ilişkiye bağlı olarak, zayıf veya unowned referanslar arasında seçim yapın:
- Zayıf (Weak): Bir nesne, diğer nesne yok edilmeden önce
nilolabilir (opsiyonel değer). - Unowned: Bir nesne, diğer nesne var olduğu sürece var olur (opsiyonel olmayan değer).
ARC ayrıca, sınıf örneklerini yakalayan kapanımların (closures) kullandığı belleği de yönetir. Güçlü referans döngüleri, bir kapanımın sınıf örneğini yakalaması ve bu örneğin de kapanıma güçlü referansla bağlı olması durumunda oluşabilir. Bunu önlemek için, kapanımlarda yakalama listeleri (capture lists) kullanılır.
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
// Capture list yok, güçlü döngü olası
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name)>"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) sonlandırılıyor")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "merhaba, dünya")
print(paragraph!.asHTML())
paragraph = nil // HTMLElement sonlandırılmıyor
Çözüm, [weak self] kullanımı:
class AnHTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = { [weak self] in // weak self kullanımı
guard let self = self else { return "" } // self’in var olup olmadığını kontrol et
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name)>"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) sonlandırılıyor")
}
}
var paragraph: AnHTMLElement? = AnHTMLElement(name: "p", text: "merhaba, dünya")
print(paragraph!.asHTML())
paragraph = nil // AnHTMLElement sonlandırılıyor
[unowned self] kullanımı, eğer sınıf örneğinin (self) kapanmadan önce nil olmayacağından eminseniz, mümkündür.
ARC, manuel yönetimle karşılaştırıldığında Swift'te bellek yönetimini büyük ölçüde kolaylaştırır, ancak sızıntıları önlemek için referans türlerinin anlaşılmasını gerektirir.