Press ESC to close

Swift Observer Yapısı Kurma

Merhaba arkadaşlar, bu yazımızda Swift ile nasıl Observer  yapısı kurulur bundan bahsedeceğiz. Öncelikle neden bir yapıya ihtiyaç duyuyoruz konusuyla başlayabiliriz. NotificationCenter ile yapamaz mıydık?

Projenizde bir yer, bir obje değiştiğinde buna direkt veya dolaylı olarak bağlanan sınıfların haberdar olması gerekir. Bu durumu önceden Notification Center ile yönetiyorduk. Notification Center’ın yönetilmesi zordur ve istenilen her yerden herhangi bir kısıtlama olmadan tetiklenebilir veya dinlenebilir. Bu büyük projelerde büyük sorunlara yol açabilir. Çünkü herhangi bir kısıtınız yoktur. Aynı zamanda kullanış açısından da eski kalmış bir yapı. Bu yüzden bir Observer yapısı kurmak çok daha mantıklı geliyor. 

Bu yazıda vereceğim örnekte aslında canlıda olan bir uygulamam üzerinden örnek vereceğim. Fintracker – Budget Saver adlı uygulamamda döviz kuru değişince diğer sayfalarında bundan haberdar olması gerekip buna göre aksiyon alması gerekiyordu. Çünkü döviz kuru değişmesine rağmen eski döviz kuruyla kalmasını istemeyiz. Bu sebeple döviz kuru değişirse bununla alakalı her yerin değişmesi gerekir.

Bu işlem için öncelikle bir tane protocol oluşturuyoruz. LocallyCurrencyUpdaterObserver adında bir protocol oluşturdum. Bu protocol aslında döviz değişikliklerini dinleyen objeler için. Döviz değişikliğini dinlemek isteyen sınıflar bu protocol’u implemente etmek zorundalar. 

İkinci aşama olarak ise ObservableLocallyCurrencyUpdater adında bir protocol oluşturuyoruz. Bu protocol ile aslında observer’ları tutan. Kendini observer olarak ekleyen ve observer’lardan silen, ayrıca observerlara haber veren fonksiyonlar mevcut. Bu protocol’e ayrıca bir extension yazmamız gerekli. Bu extension ile beraber default olarak implementasyonumuzu yapıyoruz.

protocol LocallyCurrencyUpdaterObserver: AnyObject {
    func onCurrencyUpdated()
}

protocol ObservableLocallyCurrencyUpdater: AnyObject {
    var observers: [LocallyCurrencyUpdaterObserver] { get set }

    func addObserver(_ observer: LocallyCurrencyUpdaterObserver)
    func removeObserver(_ observer: LocallyCurrencyUpdaterObserver)
    func notifyObservers()
}

extension ObservableLocallyCurrencyUpdater {
    func addObserver(_ observer: LocallyCurrencyUpdaterObserver) {
        observers.append(observer)
    }

    func removeObserver(_ observer: LocallyCurrencyUpdaterObserver) {
        if let index = observers.firstIndex(where: { $0 === observer }) {
            observers.remove(at: index)
        }
    }

    func notifyObservers() {
        observers.forEach { $0.onCurrencyUpdated() }
    }
}

Protocol’leri oluşturduktan sonra implementasyona başlayabiliriz. Döviz ile alakalı update işlemlerini yaptığım bir sınıfım var. İsimlendirmesi her ne kadar güzel olmasa da kendisi iş görüyor. Bu sınıf aslında tüm döviz işlemlerini yönetiyor. Bu sınıf üstte oluşturduğumuz protocol’ü implemente etmeli. Böylelikle observer’ları yönetebilecek. Dikkat ettiyseniz bu protocol’ün herhangi bir fonksiyonunu implemente etmedik. Çünkü bunu zaten extension ile yapmıştık. Eğer kullanıcı döviz tercihini değiştirirse bu sınıfta bulunan fonksiyonu çağırıyor ve local database’üzerinden değişiklik sağlanıyor. Sağlandıktan sonra ise observar’lara haber veriyor.

final class CurrencyHelper: ObservableLocallyCurrencyUpdater {
    var observers: [LocallyCurrencyUpdaterObserver] = []

    let currencies: [Currency] = [.dollar, .euro, .turkishLira, .gramGold]

    func changeDefaultCurrency(currency: Currency) {
        SettingsService.updateDefaultCurrency(currency: currency)
        notifyObservers()
    }
}

Bir sınıfının veya ViewController’ın buraya kendini observer olarak ekleyebilmesi için LocallyCurrencyUpdaterObserver protocol’unu implemente etmesi gerekiyor. Aynı zamanda kendinini observer olarak eklemeli. Aşağıdaki gibi bir impelentasyondan sonra sonuç harika. 

import UIKit

final class StatsViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        CurrencyHelper.shared.addObserver(self)
        configure()
    }

    deinit {
        CurrencyHelper.shared.removeObserver(self)
    }
}

// MARK: - LocallyCurrencyUpdaterObserver
extension StatsViewController: LocallyCurrencyUpdaterObserver {
    func onCurrencyUpdated() {
        tableView.reloadData()
    }
}

Sorularınız veya farklı düşüncelerini olursa mail atarak veya yorum atarak ulaşabilirsiniz. İyi çalışmalar.

Bir yanıt yazın

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