Что такое Observer? Как его использовать?ios-59

Что такое Observer?

Observer (Наблюдатель) — это поведенческий паттерн проектирования, который создает механизм подписки для уведомления множества объектов об изменениях состояния наблюдаемого объекта. В iOS он реализован несколькими способами.

Основные реализации Observer в iOS

1. NotificationCenter

// Отправка уведомления
NotificationCenter.default.post(
    name: Notification.Name("DataUpdated"),
    object: nil,
    userInfo: ["data": newData]
)

// Подписка на уведомление
NotificationCenter.default.addObserver(
    self,
    selector: #selector(handleDataUpdate(_:)),
    name: Notification.Name("DataUpdated"),
    object: nil
)

// Обработчик
@objc func handleDataUpdate(_ notification: Notification) {
    guard let data = notification.userInfo?["data"] as? DataType else { return }
    updateUI(with: data)
}

// Отмена подписки
deinit {
    NotificationCenter.default.removeObserver(self)
}

2. KVO

class ObservedObject: NSObject {
    @objc dynamic var value: String = "" // Помечаем как динамическое свойство
}

let object = ObservedObject()
var observation: NSKeyValueObservation?

// Настройка наблюдения
observation = object.observe(\.value, options: [.new, .old]) { object, change in
    print("Value changed from \(change.oldValue ?? "") to \(change.newValue ?? "")")
}

// Изменение значения
object.value = "New Value" // Вызовет обработчик

// Отмена наблюдения
observation?.invalidate()

3. Combine Framework

import Combine

class DataModel {
    @Published var data: String = "" // Наблюдаемое свойство
}

let model = DataModel()
var cancellables = Set<AnyCancellable>()

// Подписка
model.$data
    .sink { newValue in
        print("Data updated to \(newValue)")
    }
    .store(in: &cancellables)

// Изменение значения
model.data = "Updated Data" // Вызовет подписчика

4. SwiftUI

class UserSettings: ObservableObject {
    @Published var isLoggedIn = false
}

struct ContentView: View {
    @ObservedObject var settings = UserSettings()

    var body: some View {
        Toggle("Logged In", isOn: $settings.isLoggedIn)
    }
}

Когда использовать Observer?

  1. Изменения состояния, требующие реакции нескольких компонентов
  2. Слабо связанные компоненты системы
  3. Рассылка событий многим подписчикам
  4. Обновления UI при изменении данных

Сравнение подходов

СпособПлюсыМинусы
NotificationCenter Простота, широковещательность Нетипобезопасность, строковые ключи
KVO Автоматическое наблюдение Сложный API, требует NSObject
Combine Типобезопасность, мощный API Только iOS 13+, кривая обучения
SwiftUI Binding Интеграция с UI Только для SwiftUI

Лучшие практики

  1. Для простых проектов — NotificationCenter
  2. Для наблюдения за свойствами — Combine или KVO
  3. Для SwiftUI — @Published и @ObservedObject
  4. Всегда отменяйте подписки чтобы избежать утечек памяти

Пример реального использования

class UserViewModel {
    @Published var username: String = ""
    @Published var isLoading = false

    private var cancellables = Set<AnyCancellable>()

    func fetchUser() {
        isLoading = true
        NetworkService.fetchUser()
            .receive(on: DispatchQueue.main)
            .sink(
                receiveCompletion: { [weak self] _ in
                    self?.isLoading = false
                },
                receiveValue: { [weak self] user in
                    self?.username = user.name
                }
            )
            .store(in: &cancellables)
    }
}

Потенциальные проблемы

  1. Утечки памяти при неправильной отмене подписок
  2. Дублирование уведомлений при множественной подписке
  3. Порядок обработки не гарантирован между разными наблюдателями
  4. Многопоточность требует явного указания очереди

Резюмируем

Observer — мощный паттерн для реактивного программирования в iOS. Выбор реализации зависит от:

  • Версии iOS (Combine доступен с iOS 13)
  • Сложности наблюдения
  • Требований к типобезопасности
  • Архитектуры приложения

Современные приложения все чаще используют Combine и SwiftUI-механизмы, но NotificationCenter и KVO остаются актуальными для legacy-кода. Главное — соблюдать правила отмены подписок и учитывать потокобезопасность.

Для новых проектов рекомендуется изучать Combine — это будущее реактивного программирования в экосистеме Apple.