Press ESC to close

Strong – Unowned – Weak Tipleri

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)

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir