Observer — isang pattern ng pag-uugali kung saan ang isang bagay (tagapaglathala) ay nag-aabiso ng maraming tagasuskribi tungkol sa mga pagbabago sa estado nito. Sa pag-develop ng mobile, ang Observer ay nasa puso ng mga reaktibong mekanismo: ang UI ay nag-subscribe sa mga pagbabago ng data at awtomatikong nag-a-update. Ang pattern ay ipinatupad sa NotificationCenter sa iOS at LiveData/Flow sa Android. Higit pa — sa Refactoring Guru: Observer.
Mga Pangunahing Punto
Observer (tagamasid) — isang GoF pattern ng pag-uugali na tumutukoy sa dependency na «isa-sa-marami» sa pagitan ng mga bagay. Kapag binago ng isang bagay (Subject o Observable) ang estado nito, lahat ng umaasang bagay (Observers) ay awtomatikong naaabiso at naa-update. Ang pattern ay nagpapatupad ng mahinang pagkabit: hindi alam ng tagapaglathala ang mga kongkretong klase ng mga tagasuskribi — alam lang na nagpapatupad sila ng interface ng Observer.
Istraktura ng Observer ay may kasamang interface ng Subject na may mga pamamaraang attach(), detach(), notify() at interface ng Observer na may pamamaraang update(). Ang ConcreteSubject ay nag-iimbak ng estado at listahan ng mga tagasuskribi. Ang ConcreteObserver ay nagpapatupad ng update() at tumutugon sa mga pagbabago. Sa pag-develop ng mobile, ang klasikong implementasyon ng GoF ay bihirang matagpuan — pinapalitan ito ng mga built-in na mekanismo: NotificationCenter, Combine, Flow, LiveData, na nagpapatupad ng parehong ideya gamit ang modernong API.
Modelong Push vs Pull — sa modelong Push, ang Subject ay nagpapadala ng data sa lahat ng tagasuskribi (NotificationCenter.post). Sa modelong Pull, ang Subject ay nag-aabiso lamang, at ang tagasuskribi mismo ang kumukuha ng data. Ang Android LiveData ay gumagamit ng Push (ang data ay ipinapasa sa observe()), sinusuportahan ng RxJava/Flow ang parehong modelo. Ang pagpili ay depende sa gawain: ang Push ay mas simple para sa mga update ng UI, ang Pull ay mas mahusay para sa malalaking volume ng data na maaaring hindi gustong matanggap ng tagasuskribi.
NotificationCenter — ang built-in na mekanismo ng iOS/macOS para sa pagpapatupad ng Observer. Ang tagapaglathala ay nagpapadala ng Notification sa pamamagitan ng NotificationCenter.default.post(name:, object:, userInfo:). Ang tagasuskribi ay nagrerehistro sa pamamagitan ng addObserver(forName:, queue:, using:). Ang NotificationCenter ay sumusuporta sa mga pinangalanang abiso (Notification.Name) at maaaring magpasa ng anumang data sa userInfo. UIKeyboardWillShowNotification, UIApplicationDidEnterBackgroundNotification — mga halimbawa ng sistema.
extension Notification.Name {
static let userDidLogin = Notification.Name("userDidLogin")
}
// Tagapaglathala
NotificationCenter.default.post(
name: .userDidLogin,
object: nil,
userInfo: ["userId": "123"]
)
// Tagasuskribi
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 }
// Ang tagasuskribi ay tumutugon sa kaganapan
self?.loadProfile(userId: userId)
}
observers.append(observer)
}
func stopObserving() {
observers.forEach { NotificationCenter.default.removeObserver($0) }
observers.removeAll()
}
}
Combine framework — isang modernong reaktibong alternatibo sa NotificationCenter, available mula noong iOS 13. Publisher (NotificationCenter, URLSession.Timer) — tagapaglathala, Subscriber (sink, assign) — tagasuskribi. Nagdaragdag ang Combine ng mga operator (map, filter, combineLatest) para sa pagbabago ng daloy ng data. @Published — property wrapper na awtomatikong nag-aabiso sa mga tagasuskribi tungkol sa mga pagbabago. Sa MVVM na may SwiftUI, pinapalitan ng Combine ang NotificationCenter para sa pag-uugnay ng ViewModel at View.
KVO (Key-Value Observing) — isang lumang mekanismo ng ObjC/Swift para sa pagmamasid sa mga indibidwal na pag-aari ng mga bagay. @objc dynamic var name: String — naobserbahang pag-aari. observe(.name) — subscription. Ang KVO ay gumagana lamang sa mga klase na katugma sa @objc at pamana ng ObjC. Inirerekomenda ng Apple ang Combine at @Published sa halip na KVO sa mga bagong proyekto. Ang KVO ay nananatiling may kaugnayan para sa compatibility ng UIKit sa mga hybrid na proyekto.
LiveData — isang bahagi ng Android Architecture Components para sa pagpapatupad ng Observer. Isang klase ng Observable na nag-aabiso sa mga tagasuskribi tungkol sa mga pagbabago ng data. Isinasaalang-alang ng LiveData ang lifecycle: ang mga tagasuskribi (LifecycleOwner) ay awtomatikong nag-a-unsubscribe kapag nawasak. Ang LiveData ay modelong Push: ang data ay ipinapasa sa observe(). Ang LiveData ay ang pangunahing bloke ng gusali ng MVVM sa Android bago ang pagpapakilala ng Jetpack Compose.
// ViewModel — tagapaglathala
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 — tagasuskribi
class UserFragment : Fragment() {
private val viewModel: UserViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.user.observe(viewLifecycleOwner) { user ->
// Ang tagasuskribi ay tumutugon sa mga pagbabago
userName.text = user?.name
userEmail.text = user?.email
}
}
}
StateFlow at SharedFlow — mga reaktibong uri mula sa Kotlin Coroutines na pumalit sa LiveData sa Jetpack Compose. StateFlow — observable state holder na may nakapirming kasalukuyang halaga. SharedFlow — nako-configure na hot flow na walang estado, angkop para sa isang beses na mga kaganapan (nabigasyon, toast). Ang parehong uri ay malapit na isinama sa Compose: collectAsState(), collectAsEffect(). Ang StateFlow ay sapilitan sa mga modernong proyekto ng Android na may Compose.
LiveData vs StateFlow — ang LiveData ay nakatali sa Android Lifecycle, ang StateFlow ay independiyente sa platform. Sinusuportahan ng StateFlow ang coroutines, operator (map, filter) at sinusuri nang walang mga dependency sa Android. Ang LiveData ay mas simple para sa compatibility ng Java. Inirerekomenda ng Google ang StateFlow para sa mga bagong proyekto na may Kotlin + Compose, LiveData — para sa suporta ng mga lumang proyekto o Java code.
Mga tagas ng memorya (memory leaks) — ang pangunahing problema ng Observer nang walang tamang pamamahala ng subscription. Kung ang isang tagasuskribi (Activity, Fragment, UIViewController) ay nawasak ngunit hindi nag-unsubscribe, ang tagapaglathala ay patuloy na humahawak ng sanggunian dito, at hindi mapapalaya ng garbage collector ang memorya. Sa Android, ang LifecycleOwner (Activity/Fragment) ay dapat tumawag ng removeObserver() o gumamit ng observe(viewLifecycleOwner). Sa iOS — removeObserver sa deinit o disposeBag sa Combine.
| Platform | Mekanismo ng Observer | Awtomatikong pag-unsubscribe | Manual na pag-unsubscribe |
|---|---|---|---|
| iOS | NotificationCenter | Hindi | removeObserver() sa deinit |
| iOS | Combine (sink) | Hindi | store(in: &bag) — DisposeBag |
| iOS | KVO | Hindi | removeObserver() sa deinit |
| Android | LiveData | Oo (LifecycleOwner) | removeObserver() opsyonal |
| Android | StateFlow | Sa pamamagitan ng viewModelScope | cancel() Job sa pag-unsubscribe |
| Android | RxJava | Hindi | dispose() sa CompositeDisposable |
Mahinang sanggunian (weak reference) sa mga tagasuskribi — sa bloke ng subscription gamitin ang [weak self] sa Swift at sumangguni sa lifecycle scope sa Kotlin. Awtomatikong pinamamahalaan ng LiveData ang subscription sa pamamagitan ng LifecycleOwner — ang subscription ay aktibo lamang kapag ang Lifecycle ay nasa estado ng STARTED o RESUMED. Ang StateFlow sa Compose ay gumagamit ng collectAsState() na isinasaalang-alang ang lifecycle. Ang NotificationCenter sa iOS ay nangangailangan ng tahasang [weak self], dahil ang closure ay malakas na sumasangguni sa self.
Observer (GoF) at Publisher-Subscriber (PubSub) — magkatulad ngunit magkaibang mga pattern. Sa Observer, direktang inaabiso ng tagapaglathala ang mga tagasuskribi sa pamamagitan ng pagtawag sa kanilang mga pamamaraan. Alam ng tagapaglathala ang mga tagasuskribi (nag-iimbak ng listahan). Sa PubSub, hindi alam ng tagapaglathala at tagasuskribi ang isa’t isa — may tagapamagitan (Event Bus, Message Queue, NotificationCenter) sa pagitan nila. Ang tagapaglathala ay nagpapadala ng mensahe sa isang channel, ang tagasuskribi ay nakikinig sa channel. Ang PubSub ay nagbibigay ng mas mahinang pagkabit.
Mga halimbawa ng PubSub sa pag-develop ng mobile — ang NotificationCenter sa iOS ay maaaring ituring na PubSub: hindi kilala ng tagapaglathala ang mga tagasuskribi — nagpo-post lamang ito ng abiso. EventBus o Otto sa Android (luma na). SharedFlow na may BroadcastChannel — PubSub sa mundo ng Kotlin. Sa mga distributed system, ang PubSub ay ipinatutupad sa pamamagitan ng RabbitMQ, Kafka, Google PubSub. Para sa pag-develop ng mobile, ang PubSub ay kapaki-pakinabang sa modular na arkitektura, kung saan ang mga module ay hindi dapat umasa sa isa’t isa.
Ano ang pipiliin — para sa mga update ng UI (ViewModel → View) gamitin ang Observer (LiveData, StateFlow, @Published). Para sa mga inter-module na kaganapan (awtorisasyon, pag-logout, pagbabago ng tema) — PubSub (SharedFlow, NotificationCenter, EventBus). Ang Observer ay mas simple at mahusay sa loob ng isang screen, ang PubSub ay mas nababaluktot para sa mga pandaigdigang kaganapan ngunit mas mahirap i-debug dahil sa mga implicit na dependency.
Mga Madalas Itanong
Ang StateFlow ay isang uri na independiyente sa platform mula sa Kotlin Coroutines, ang LiveData ay nakatali sa Android Lifecycle. Sinusuportahan ng StateFlow ang coroutines at operator, sinusuri nang walang Android. Awtomatikong pinamamahalaan ng LiveData ang subscription sa pamamagitan ng LifecycleOwner. Inirerekomenda ng Google ang StateFlow para sa mga bagong proyekto na may Kotlin + Compose, LiveData — para sa compatibility ng Java.
Gamitin ang [weak self] sa closure ng handler at tawagan ang removeObserver() sa deinit. Mag-imbak ng sanggunian sa observer (NSObjectProtocol) at tanggalin ito sa pagkasira ng bagay. Sa Combine, gamitin ang AnyCancellable at store(in:) para sa awtomatikong pag-unsubscribe kapag pinalaya ang DisposeBag.
Oo, sinusuportahan ng SwiftUI ang ObservableObject na may @Published at @StateObject/@ObservedObject — ito ay isang built-in na implementasyon ng Observer. Awtomatikong inaabiso ng @Published ang View tungkol sa mga pagbabago. Hindi kinakailangan ang Combine: ang ObservableObject ay gumagamit ng objectWillChange Publisher na naka-embed sa SwiftUI. Nagdaragdag ang Combine ng mga operator para sa pagbabago ng daloy.
SharedFlow — para sa isang beses na mga kaganapan (nabigasyon, toast, Snackbar) kung saan hindi kailangan ang kasalukuyang halaga. StateFlow — para sa estado ng UI (listahan ng data, progreso ng pag-load) kung saan kailangan ang kasalukuyang snapshot. Ang SharedFlow ay walang value property at hindi ibinabalik ang huling halaga sa mga bagong tagasuskribi.
Ang KVO ay isang lumang mekanismo ng ObjC, nangangailangan ng @objc dynamic at gumagana lamang sa mga klase na nagmamana ng NSObject. Ang Combine ay isang modernong Swift framework, type-safe, na may mga operator at integrasyon sa SwiftUI. Pinapalitan ng Combine ang KVO at NotificationCenter. Inirerekomenda ng Apple ang Combine para sa mga bagong proyekto, KVO — para lamang sa suporta ng lumang code.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din