Observer — кључни појмови шаблона претплате на промене

Аутор: IT Sectr Објављено: 2026-02-17 Време читања: 7 мин

Observer — образац понашања у којем један објекат (издавач) обавештава више претплатника о променама свог стања. У мобилном развоју, Observer лежи у основи реактивних механика: UI се претплаћује на промене података и аутоматски се ажурира. Образац је имплементиран у NotificationCenter на iOS-у и LiveData/Flow на Android-у. Детаљније — на Refactoring Guru: Observer.

Главно

  • Observer — образац претплате: један издавач, више претплатника
  • NotificationCenter — уграђена имплементација Observer-а у iOS/macOS
  • Flow и LiveData — реактивне имплементације Observer-а у Android-у
  • Push vs Pull — издавач може слати податке или обавештавати о догађајима
  • Цурење меморије — претплатници морају да се одјаве ради спречавања цурења

Шта је Observer: суштина шаблона посматрач?

Observer (посматрач) — GoF образац понашања који дефинише зависност „један према многима" између објеката. Када један објекат (Subject или Observable) промени стање, сви зависни објекти (Observers) се аутоматски обавештавају и ажурирају. Образац реализује слабо повезивање: издавач не зна конкретне класе претплатника — само да имплементирају интерфејс Observer.

Структура Observer-а укључује интерфејс Subject са методама attach(), detach(), notify() и интерфејс Observer са методом update(). ConcreteSubject чува стање и листу претплатника. ConcreteObserver имплементира update() и реагује на промене. У мобилном развоју, класична GoF имплементација се ретко среће — замењују је уграђени механизми: NotificationCenter, Combine, Flow, LiveData, који реализују исту идеју са модерним API-јем.

Push vs Pull модел — у Push моделу Subject шаље податке свим претплатницима (NotificationCenter.post). У Pull моделу Subject само обавештава, а претплатник сам преузима податке. Android LiveData користи Push (подаци се преносе у observe()), RxJava/Flow подржавају оба модела. Избор зависи од задатка: Push је једноставнији за UI ажурирања, Pull је ефикаснији за велике количине података које претплатник можда не жели да прима.

Observer у iOS-у: NotificationCenter, Combine и KVO

NotificationCenter — уграђени механизам iOS/macOS за имплементацију Observer-а. Издавач шаље Notification путем NotificationCenter.default.post(name:, object:, userInfo:). Претплатник се региструје путем addObserver(forName:, queue:, using:). NotificationCenter подржава именована обавештења (Notification.Name) и може преносити било које податке у userInfo. UIKeyboardWillShowNotification, UIApplicationDidEnterBackgroundNotification — системски примери.

swift
extension Notification.Name {
    static let userDidLogin = Notification.Name("userDidLogin")
}

// Издавач
NotificationCenter.default.post(
    name: .userDidLogin,
    object: nil,
    userInfo: ["userId": "123"]
)

// Претплатник
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 }
            // Претплатник реагује на догађај
            self?.loadProfile(userId: userId)
        }
        observers.append(observer)
    }

    func stopObserving() {
        observers.forEach { NotificationCenter.default.removeObserver($0) }
        observers.removeAll()
    }
}

Combine framework — модерна реактивна алтернатива за NotificationCenter, доступна од iOS 13. Publisher (NotificationCenter, URLSession.Timer) — издавач, Subscriber (sink, assign) — претплатник. Combine додаје операторе (map, filter, combineLatest) за трансформацију тока података. @Published — property wrapper који аутоматски обавештава претплатнике о променама. У MVVM са SwiftUI, Combine замењује NotificationCenter за повезивање ViewModel и View.

KVO (Key-Value Observing) — стари ObjC/Swift механизам за посматрање појединачних својстава објеката. @objc dynamic var name: String — посматрано својство. observe(.name) — претплата. KVO ради само са @objc-компатибилним класама и ObjC наслеђем. Apple препоручује Combine и @Published уместо KVO у новим пројектима. KVO остаје актуелан за UIKit компатибилност у хибридним пројектима.

Observer у Android-у: LiveData, StateFlow и SharedFlow

LiveData — компонента Android Architecture Components за имплементацију Observer-а. Observable класа која обавештава претплатнике о променама података. LiveData узима у обзир животни циклус: претплатници (LifecycleOwner) се аутоматски одјављују при уништењу. LiveData је Push модел: подаци се преносе у observe(). LiveData је основни градивни блок MVVM у Android-у пре увођења Jetpack Compose.

kotlin
// ViewModel — издавач
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 — претплатник
class UserFragment : Fragment() {
    private val viewModel: UserViewModel by viewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        viewModel.user.observe(viewLifecycleOwner) { user ->
            // Претплатник реагује на промене
            userName.text = user?.name
            userEmail.text = user?.email
        }
    }
}

StateFlow и SharedFlow — реактивни типови из Kotlin Coroutines који су заменили LiveData у Jetpack Compose-у. StateFlow — observable state holder са фиксном тренутном вредношћу. SharedFlow — конфигурабилни hot flow без стања, погодан за једнократне догађаје (навигација, тостови). Оба типа су уско интегрисана са Compose-ом: collectAsState(), collectAsEffect(). StateFlow је обавезан у савременим Android пројектима са Compose-ом.

LiveData vs StateFlow — LiveData је везан за Android Lifecycle, StateFlow је платформски независан. StateFlow подржава coroutines, операторе (map, filter) и тестира се без Android зависности. LiveData је једноставнији за Java компатибилност. Google препоручује StateFlow за нове пројекте на Kotlin + Compose, LiveData — за подршку старих пројеката или Java кода.

Управљање претплатама и цурење меморије

Цурење меморије (memory leaks) — главни проблем Observer-а без правилног управљања претплатама. Ако је претплатник (Activity, Fragment, UIViewController) уништен, али се није одјавио, издавач наставља да држи референцу на њега, и garbage collector не може да ослободи меморију. У Android-у, LifecycleOwner (Activity/Fragment) треба да позове removeObserver() или да користи observe(viewLifecycleOwner). У iOS-у — removeObserver у deinit или disposeBag у Combine-у.

ПлатформаМеханизам ObserverАутоматска одјаваРучна одјава
iOSNotificationCenterНеremoveObserver() у deinit
iOSCombine (sink)Неstore(in: &bag) — DisposeBag
iOSKVOНеremoveObserver() у deinit
AndroidLiveDataДа (LifecycleOwner)removeObserver() опционално
AndroidStateFlowПреко viewModelScopecancel() Job при одјави
AndroidRxJavaНеdispose() у CompositeDisposable

Слаба референца (weak reference) код претплатника — у блоку претплате користите [weak self] у Swift-у и реферишите се на lifecycle scope у Kotlin-у. LiveData аутоматски управља претплатом путем LifecycleOwner-а — претплата је активна само када је Lifecycle у стању STARTED или RESUMED. StateFlow у Compose-у користи collectAsState() са уважавањем lifecycle-а. NotificationCenter у iOS-у захтева експлицитно [weak self], јер closure јако референцира self.

Observer vs Publisher-Subscriber: у чему је разлика

Observer (GoF) и Publisher-Subscriber (PubSub) — слични, али различити обрасци. У Observer-у, издавач директно обавештава претплатнике позивањем њихових метода. Издавач зна за претплатнике (чува листу). У PubSub-у, издавач и претплатник не знају један за другог — између њих се налази посредник (Event Bus, Message Queue, NotificationCenter). Издавач шаље поруку на канал, претплатник слуша канал. PubSub обезбеђује слабије повезивање.

Примери PubSub-а у мобилном развоју — NotificationCenter у iOS-у се може сматрати PubSub-ом: издавач не зна претплатнике — само објављује обавештење. EventBus или Otto у Android-у (застарели). SharedFlow са BroadcastChannel — PubSub у свету Kotlin-а. У дистрибуираним системима, PubSub се реализује путем RabbitMQ, Kafka, Google PubSub. За мобилни развој, PubSub је користан у модуларној архитектури, где модули не треба да зависе једни од других.

Шта изабрати — за UI ажурирања (ViewModel → View) користите Observer (LiveData, StateFlow, @Published). За међумодулне догађаје (ауторизација, одјава, промена теме) — PubSub (SharedFlow, NotificationCenter, EventBus). Observer је једноставнији и ефикаснији у оквиру једног екрана, PubSub је флексибилнији за глобалне догађаје, али тежи за отклањање грешака због имплицитних зависности.

Често постављана питања

По чему се StateFlow разликује од LiveData?

StateFlow је платформски независан тип из Kotlin Coroutines, LiveData је везан за Android Lifecycle. StateFlow подржава coroutines и операторе, тестира се без Android-а. LiveData аутоматски управља претплатом путем LifecycleOwner-а. Google препоручује StateFlow за нове пројекте на Kotlin + Compose, LiveData — за Java компатибилност.

Како избећи цурење меморије са NotificationCenter-ом?

Користите [weak self] у closure-у handler-а и позовите removeObserver() у deinit-у. Чувајте референцу на observer (NSObjectProtocol) и уклоните га при уништењу објекта. У Combine-у користите AnyCancellable и store(in:) за аутоматску одјаву при ослобађању DisposeBag-а.

Може ли се Observer користити у SwiftUI-ју без Combine-а?

Да, SwiftUI подржава ObservableObject са @Published и @StateObject/@ObservedObject — ово је уграђена имплементација Observer-а. @Published аутоматски обавештава View о променама. Combine није обавезан: ObservableObject користи objectWillChange Publisher уграђен у SwiftUI. Combine додаје операторе за трансформацију токова.

Када користити SharedFlow уместо StateFlow?

SharedFlow — за једнократне догађаје (навигација, тостови, Snackbar) где није потребна тренутна вредност. StateFlow — за стање UI-ја (листа података, напредак учитавања) где је потребан тренутни снимак. SharedFlow нема value својство и не враћа последњу вредност новим претплатницима.

Која је разлика између KVO и Combine-а у iOS-у?

KVO је застарели ObjC механизам, захтева @objc dynamic и ради само са класама које наслеђују NSObject. Combine је модеран Swift framework, типски безбедан, са операторима и интеграцијом са SwiftUI-јем. Combine замењује KVO и NotificationCenter. Apple препоручује Combine за нове пројекте, KVO — само за подршку застарелом коду.

Резиме

  • Observer — образац понашања за обавештавање претплатника о променама
  • iOS NotificationCenter — PubSub имплементација са именованим обавештењима
  • iOS Combine — реактивни framework са Publisher и Subscriber
  • Android LiveData — lifecycle-aware Observer из Android Architecture Components
  • Android StateFlow — реактивни state holder за Compose и корутине
  • Управљање меморијом — обавезна одјава ради спречавања цурења
  • Observer vs PubSub — директна претплата vs посредник за слабо повезивање

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође