Observer — bir nesnenin (yayıncı) durumundaki değişiklikler hakkında birden çok aboneyi bilgilendirdiği davranışsal bir desendir. Mobil geliştirmede Observer, reaktif mekanizmaların temelini oluşturur: UI veri değişikliklerine abone olur ve otomatik olarak güncellenir. Desen, iOS'ta NotificationCenter ve Android'de LiveData/Flow ile uygulanır. Daha fazla ayrıntı için Refactoring Guru: Observer adresini ziyaret edin.
Önemli noktalar
Observer — nesneler arasında bire-çok bağımlılığı tanımlayan bir GoF davranışsal desenidir. Bir nesne (Subject veya Observable) durumunu değiştirdiğinde, bağımlı tüm nesneler (Observers) otomatik olarak bilgilendirilir ve güncellenir. Desen gevşek bağlantı uygular: yayıncı abonelerin belirli sınıflarını bilmez — yalnızca Observer arayüzünü uyguladıklarını bilir.
Observer yapısı, attach(), detach(), notify() yöntemlerine sahip Subject arayüzünü ve update() yöntemine sahip Observer arayüzünü içerir. ConcreteSubject durumu ve abone listesini saklar. ConcreteObserver update() yöntemini uygular ve değişikliklere tepki verir. Mobil geliştirmede, GoF'nin klasik uygulaması nadirdir — yerini NotificationCenter, Combine, Flow, LiveData gibi yerleşik mekanizmalar alır; bunlar aynı fikri modern API'lerle uygular.
Push vs Pull modeli — Push modelinde Subject tüm abonelere veri gönderir (NotificationCenter.post). Pull modelinde Subject yalnızca bildirim yapar ve abone veriyi kendisi ister. Android LiveData Push kullanır (veri observe() içinde iletilir), RxJava/Flow her iki modeli de destekler. Seçim göreve bağlıdır: Push UI güncellemeleri için daha basittir, Pull abonenin almak istemeyebileceği büyük veri hacimleri için daha verimlidir.
NotificationCenter — Observer'ı uygulamak için yerleşik bir iOS/macOS mekanizmasıdır. Yayıncı, NotificationCenter.default.post(name:, object:, userInfo:) aracılığıyla bir Notification gönderir. Abone, addObserver(forName:, queue:, using:) aracılığıyla kaydolur. NotificationCenter adlandırılmış bildirimleri (Notification.Name) destekler ve userInfo içinde herhangi bir veri iletebilir. UIKeyboardWillShowNotification, UIApplicationDidEnterBackgroundNotification — sistem örnekleri.
extension Notification.Name {
static let userDidLogin = Notification.Name("userDidLogin")
}
// Yayıncı
NotificationCenter.default.post(
name: .userDidLogin,
object: nil,
userInfo: ["userId": "123"]
)
// Abone
class ProfileViewModel {
private var observers: [NSObjectProtocol] = []
func startObserving() {
let observer = NotificationCenter.default.addObserver(
forName: .userDidLogin,
object: nil,
queue: .main
) { [weak self] notification in
guard let userId = notification.userInfo?["userId"] as? String else { return }
// Abone olaya tepki verir
self?.loadProfile(userId: userId)
}
observers.append(observer)
}
func stopObserving() {
observers.forEach { NotificationCenter.default.removeObserver($0) }
observers.removeAll()
}
}
Combine framework — iOS 13'te tanıtılan, NotificationCenter'a modern bir reaktif alternatiftir. Publisher (NotificationCenter, URLSession, Timer) — yayıncı, Subscriber (sink, assign) — abone. Combine, veri akışı dönüşümü için operatörler (map, filter, combineLatest) ekler. @Published — aboneleri değişiklikler hakkında otomatik olarak bilgilendiren bir property wrapper'dır. SwiftUI ile MVVM'de Combine, ViewModel ve View'i bağlamak için NotificationCenter'ın yerini alır.
KVO (Key-Value Observing) — nesnelerin tek tek özelliklerini gözlemlemek için daha eski bir ObjC/Swift mekanizmasıdır. @objc dynamic var name: String — gözlemlenebilir bir özellik. observe(.name) — abonelik. KVO yalnızca @objc uyumlu sınıflar ve ObjC kalıtımı ile çalışır. Apple yeni projelerde KVO yerine Combine ve @Published önermektedir. KVO, hibrit projelerde UIKit uyumluluğu için hala önemlidir.
LiveData — Observer'ı uygulamak için Android Architecture Components'un bir bileşenidir. Aboneleri veri değişiklikleri hakkında bilgilendiren gözlemlenebilir bir sınıftır. LiveData yaşam döngüsü bilincine sahiptir: aboneler (LifecycleOwner) yok edildiğinde otomatik olarak abonelikten çıkar. LiveData Push modelini kullanır (veri observe() içinde iletilir). LiveData, Jetpack Compose öncesi Android'de MVVM'nin temel yapı taşıdır.
// ViewModel — yayıncı
class UserViewModel : ViewModel() {
private val _user = MutableLiveData<User?>(null)
val user: LiveData<User?> = _user
fun loadUser(id: String) {
viewModelScope.launch {
val result = userRepository.getUser(id)
_user.value = result
}
}
}
// Fragment — abone
class UserFragment : Fragment() {
private val viewModel: UserViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.user.observe(viewLifecycleOwner) { user ->
// Abone değişikliklere tepki verir
userName.text = user?.name
userEmail.text = user?.email
}
}
}
StateFlow ve SharedFlow — Jetpack Compose'da LiveData'nın yerini alan Kotlin Coroutines'in reaktif türleridir. StateFlow — sabit bir geçerli değere sahip gözlemlenebilir durum tutucu. SharedFlow — durumu olmayan yapılandırılabilir bir sıcak akış, tek seferlik olaylar (gezinme, tost) için uygundur. Her iki tür de Compose ile sıkı bir şekilde entegredir: collectAsState(), collectAsEffect(). Compose ile modern Android projelerinde StateFlow zorunludur.
LiveData vs StateFlow — LiveData Android yaşam döngüsüne bağlıdır, StateFlow platformdan bağımsızdır. StateFlow coroutines, operatörler (map, filter) destekler ve Android bağımlılıkları olmadan test edilebilir. LiveData Java uyumluluğu için daha basittir. Google, Kotlin + Compose ile yeni projeler için StateFlow'u, eski projeleri veya Java kodunu sürdürmek için LiveData'yı önerir.
Bellek sızıntıları — uygun abonelik yönetimi olmadan Observer'ın ana sorunudur. Bir abone (Activity, Fragment, UIViewController) yok edilir ancak abonelikten çıkmazsa, yayıncı ona referans tutmaya devam eder ve çöp toplayıcı belleği serbest bırakamaz. Android'de LifecycleOwner (Activity/Fragment) removeObserver() çağırmalı veya observe(viewLifecycleOwner) kullanmalıdır. iOS'ta — deinit içinde removeObserver veya Combine'da disposeBag.
| Platform | Observer mekanizması | Otomatik abonelikten çıkma | Manuel abonelikten çıkma |
|---|---|---|---|
| iOS | NotificationCenter | Hayır | deinit'te removeObserver() |
| iOS | Combine (sink) | Hayır | store(in: &bag) — DisposeBag |
| iOS | KVO | Hayır | deinit'te removeObserver() |
| Android | LiveData | Evet (LifecycleOwner) | removeObserver() isteğe bağlı |
| Android | StateFlow | viewModelScope aracılığıyla | çıkışta cancel() Job |
| Android | RxJava | Hayır | CompositeDisposable'da dispose() |
Abonelerde zayıf referans — abonelik bloklarında closure kullanırken Swift'te [weak self] kullanın ve Kotlin'de yaşam döngüsü kapsamına başvurun. LiveData, LifecycleOwner aracılığıyla abonelikleri otomatik olarak yönetir — abonelik yalnızca Lifecycle STARTED veya RESUMED durumundayken aktiftir. Compose'da StateFlow, yaşam döngüsü bilinciyle collectAsState() kullanır. iOS'ta NotificationCenter, closure self'e güçlü referans tuttuğu için açık [weak self] gerektirir.
Observer (GoF) ve Yayıncı-Abone (PubSub) — benzer ancak farklı desenlerdir. Observer'da yayıncı, abonelerin yöntemlerini çağırarak doğrudan bilgilendirir. Yayıncı aboneleri bilir (bir liste saklar). PubSub'da yayıncı ve abone birbirini bilmez — aralarında bir aracı (Event Bus, Message Queue, NotificationCenter) bulunur. Yayıncı bir kanala mesaj gönderir, abone kanalı dinler. PubSub daha gevşek bağlantıya sahiptir.
Mobil geliştirmede PubSub örnekleri — iOS'ta NotificationCenter PubSub olarak kabul edilebilir: yayıncı aboneleri bilmez — sadece bir bildirim yayınlar. Android'de EventBus veya Otto (kullanımdan kaldırıldı). BroadcastChannel ile SharedFlow — Kotlin dünyasında PubSub. Dağıtık sistemlerde PubSub, RabbitMQ, Kafka, Google PubSub aracılığıyla uygulanır. Mobil geliştirme için PubSub, modüllerin birbirine bağımlı olmaması gereken modüler mimaride kullanışlıdır.
Ne seçilmeli — UI güncellemeleri (ViewModel → View) için Observer (LiveData, StateFlow, @Published) kullanın. Modüller arası olaylar (kimlik doğrulama, çıkış, tema değişikliği) için — PubSub (SharedFlow, NotificationCenter, EventBus) kullanın. Observer tek bir ekran içinde daha basit ve verimlidir, PubSub küresel olaylar için daha esnektir ancak örtük bağımlılıklar nedeniyle hata ayıklaması daha zordur.
Sıkça sorulan sorular
StateFlow, Kotlin Coroutines'in platformdan bağımsız bir türüdür, LiveData ise Android yaşam döngüsüne bağlıdır. StateFlow coroutines ve operatörleri destekler ve Android olmadan test edilebilir. LiveData, LifecycleOwner aracılığıyla abonelikleri otomatik olarak yönetir. Google, Kotlin + Compose ile yeni projeler için StateFlow'u ve Java uyumluluğu için LiveData'yı önerir.
İşleyici closure'ında [weak self] kullanın ve deinit'te removeObserver() çağırın. observer (NSObjectProtocol) referansını saklayın ve nesne yok edildiğinde kaldırın. Combine'da, DisposeBag serbest bırakıldığında otomatik abonelikten çıkma için AnyCancellable ve store(in:) kullanın.
Evet, SwiftUI, @Published ve @StateObject/@ObservedObject ile ObservableObject'i destekler — bu yerleşik bir Observer uygulamasıdır. @Published, View'i değişiklikler hakkında otomatik olarak bilgilendirir. Combine gerekli değildir: ObservableObject, SwiftUI'ye yerleşik objectWillChange Publisher'ını kullanır. Combine, akış dönüşümü için operatörler ekler.
SharedFlow — geçerli değer gerektirmeyen tek seferlik olaylar (gezinme, tost, Snackbar) için. StateFlow — geçerli anlık görüntü gerektiren UI durumu (veri listesi, yükleme ilerlemesi) için. SharedFlow'un value özelliği yoktur ve yeni abonelere son değeri döndürmez.
KVO eski bir ObjC mekanizmasıdır, @objc dynamic gerektirir ve yalnızca NSObject'ten miras alan sınıflarla çalışır. Combine modern bir Swift framework'üdür, tür güvenlidir, operatörler ve SwiftUI entegrasyonu içerir. Combine, KVO ve NotificationCenter'ın yerini alır. Apple yeni projeler için Combine'ı, yalnızca eski destek için KVO'yu önerir.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun