Merhaba arkadaşlar, bu yazımızda Swift Memory Management için en çok kullanılına yapılardan bahsedeceğiz. Daha öncesinde ARC’nin nasıl çalıştığından bahsetmiştim. O yazıya buradan ulaşabilirsiniz. Swift programlama dilinde değişken oluştururken 3 farklı tipte değişken oluşturabilirsiniz. Bunlar; Strong, Weak ve Unowned.
Strong
Bir değişken oluşturduğunuzda varsayılan olarak değişkenin tipi Strong olur. Strong tipli bir değişken Swift’in ARC yapısında referans sayısını 1 arttırır. Bu arttırım 0 olmadığı sürece bu değişken RAM’den silinmez. Bu yüzden Memory Leak oluşabilir.
Weak
Weak tipli bir değişken oluşturduğunuz zaman ARC yapısından referans sayısını 1 arttırmaz. Bu sebeple bir Retain Cycle durumu söz konusu olmayacağı için hafızadan kolayca silinir. Weak referans oluştururken değişken optional olmalıdır.
Unowned
Weak benzeri bir yapısı vardır. Farkı ise nonoptional olmasıdır. Bu sebeple değişken oluşturulurken bir değer verilmiş olması gerekiyor.
Aşağıda yapacağımız örnekte bir Memory Leak oluşturacağız ve ardından bunun çözümünü sağlayacağız. Yapacağımız örnekte bir müşteri sınıfımız ve bir de kredi kartı sınıfımız olsun. Her müşterinin bir kredi kartı olabilir ve her kredi kartının da bir müşterisi olmalı. Sınıfları tanımladıktan sonra init ve deinit fonksiyonlarına print fonksiyonlarını çalıştırarak Output’dan takip edebiliyorum.
Şunu da unutmayalım ki memory leak sadece referans tipli değişkenlerde oluşabilir. Bu sebeple struct veya enum gibi value tipli değişkenlerde memory leak söz konusu olmaz.
Sınıflarımızı oluşturduktan sonra bir müşteri ve kredi kartı oluşturup bunları oluşturduğum sınıflara set ediyorum. İşim bittikten sonra ise bu oluşturduğum değişkenleri nil set ediyorum ve RAM’den silmesini bekliyorum ama Deinit fonksiyonuna koyduğumuz fonksiyonlar çalışmadığını görüyoruz. Sebebi ise referans sayısının 0 olamaması. Aşağıdaki örnekte referans sayılarını yorum olarak yazdım.
import UIKit class Customer { let name: String var creditCard: CreditCard? init(name: String) { self.name = name print("Customer \(name) initialized") } deinit { print("Customer \(name) deinitialized") } } class CreditCard { let creditCardName: String var customer: Customer? init(creditCardName: String) { self.creditCardName = creditCardName print("CreditCard \(creditCardName) initialized") } deinit { print("CreditCard \(creditCardName) deinitialized") } } var customerOmer: Customer? var creditCardTest: CreditCard? customerOmer = Customer(name: "Omer Sezer") // customerOmer's reference count = 1 creditCardTest = CreditCard(creditCardName: "Test Credit Card") // creditCardTest's reference count = 1 customerOmer?.creditCard = creditCardTest // creditCardTest's reference count = 2 creditCardTest?.customer = customerOmer // customerOmer's reference count = 2 customerOmer = nil // customerOmer's reference count = 1 creditCardTest = nil // creditCardTest's reference count = 1
Oluşturduğum değişkenleri nil set etmeme rağmen RAM’den silinmedi ve bir daha hiç kullanmayacağım halde RAM’de duruyor. Bu şekilde bir çok değişkenimizin iç kullanılmadığını ve RAM’de boş yere durduğunu düşünün. Bir yerden sonra uygulama kasmaya ve telefon ısınmaya başlayacaktır. Bu sebeple bir değişken oluştururken bunları göz önüne almalıyız.
Çözüm olarak burada yapının mantığını kurmalıyız. Her kredi kartının bir müşteri olmalı ama her müşterinin illa bir kredi kartına sahip olması gerekmez. Bu yüzden Müşteri sınıfındaki kredi kartı değişkenini weak olarak tanımlayabiliriz. Weak olarak tanımladığımız değişkenin referansı 1 artmayacağı için Ram’den silinecek ve bir Memory Leak oluşmasını engelleyecektir.
import UIKit class Customer { let name: String weak var creditCard: CreditCard? init(name: String) { self.name = name print("Customer \(name) initialized") } deinit { print("Customer \(name) deinitialized") } } class CreditCard { let creditCardName: String var customer: Customer? init(creditCardName: String) { self.creditCardName = creditCardName print("CreditCard \(creditCardName) initialized") } deinit { print("CreditCard \(creditCardName) deinitialized") } } var customerOmer: Customer? var creditCardTest: CreditCard? customerOmer = Customer(name: "Omer Sezer") // customerOmer's reference count = 1 creditCardTest = CreditCard(creditCardName: "Test Credit Card") // creditCardTest's reference count = 1 customerOmer?.creditCard = creditCardTest // creditCardTest's reference count = 1 creditCardTest?.customer = customerOmer // customerOmer's reference count = 2 creditCardTest = nil // creditCardTest's reference count = 0 customerOmer = nil // customerOmer's reference count = 0
Daha fazla bilgiye buradan ulaşabilirsiniz. Sorularını olursa mail veya yorum atarak ulaşabilirsiniz. İyi çalışmalar.
Comments (6)
zoritoler imolsays:
Cuma Şubat 3rd, 2023 at 07:04I admire your piece of work, thanks for all the useful content.
Evden Eve Nakliyatsays:
Cuma Şubat 17th, 2023 at 09:36Hocam yazınız çok güzel bir kaynak oldu teşekkürler ancak web sitesinden görünen kodlarınıza “highlight code” bir tasarım kullanabilirseniz, kodlarınız daha iyi görünür bizim içinde daha okunur olacaktır. Emeğiniz için teşekkürler
omersezersays:
Pazar Şubat 26th, 2023 at 12:25Çok teşekkürler geri bildirim için. Bir güncellemeden sonra oldu. En kısa zamanda düzelteceğiz.
Melih Özmensays:
Pazar Şubat 19th, 2023 at 20:51güzel anlatım. teşekkürler.
Tuba Hanımsays:
Pazartesi Şubat 27th, 2023 at 14:37Hocam Xamarin mi? Flutter mı? React Native mi? Swift mi? karar veremedim bir türlü. Bu konu hakkında da bir yazı yazar mısınız?
omersezersays:
Pazartesi Şubat 27th, 2023 at 22:52Selam, yakın zamanda tecrübelerimi anlatacağım bir yazı yazarım. Umarım faydalı olur.