← Назад к вопросам

Какие абстракции в Swift похожи на event emitter?

2.0 Middle🔥 181 комментариев
#Архитектура и паттерны#Язык Swift

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Абстракции в Swift, аналогичные Event Emitter

В Swift нет прямой реализации Event Emitter как в JavaScript, но существует несколько мощных абстракций, которые реализуют похожую модель событийной архитектуры. Основная идея — возможность подписываться на события и реагировать на них асинхронно. Вот ключевые механизмы:

1. NotificationCenter (наиболее близкий аналог)

Это стандартный механизм iOS/macOS для реализации шаблона Наблюдатель (Observer). Он позволяет объектам рассылать уведомления, не зная о подписчиках.

// Отправка события
NotificationCenter.default.post(
    name: Notification.Name("UserDidLogin"),
    object: self,
    userInfo: ["username": "john"]
)

// Подписка на событие
NotificationCenter.default.addObserver(
    forName: Notification.Name("UserDidLogin"),
    object: nil,
    queue: .main
) { notification in
    if let username = notification.userInfo?["username"] as? String {
        print("Пользователь \(username) вошел в систему")
    }
}

Особенности:

  • Глобальный или кастомный центр уведомлений
  • Слабая связь между отправителем и получателями
  • Потокобезопасность при правильном использовании
  • Автоматическая отписка через removeObserver()

2. Combine Framework (современный подход)

Фреймворк Combine предоставляет реактивный подход через Publisher-Subscriber паттерн, который является более типобезопасной и мощной альтернативой.

import Combine

// Создание кастомного издателя
class UserManager {
    var loginPublisher = PassthroughSubject<String, Never>()
    
    func login(username: String) {
        // Логика входа
        loginPublisher.send(username)
    }
}

// Подписка на события
var cancellables = Set<AnyCancellable>()
let userManager = UserManager()

userManager.loginPublisher
    .sink { username in
        print("Событие входа: \(username)")
    }
    .store(in: &cancellables)

Преимущества Combine:

  • Типобезопасность и проверка на этапе компиляции
  • Операторы для трансформации событий (map, filter, debounce)
  • Интеграция с SwiftUI и async/await
  • Управление жизненным циклом через AnyCancellable

3. Delegation Pattern (протокол-ориентированный подход)

Хотя делегация обычно предполагает один получатель, ее можно адаптировать для множества подписчиков через паттерн Multicast Delegate.

protocol NetworkServiceDelegate: AnyObject {
    func didReceiveData(_ data: Data)
}

class MulticastDelegate<T> {
    private var delegates = [WeakDelegate]()
    
    func add(delegate: T) {
        delegates.append(WeakDelegate(delegate: delegate as AnyObject))
    }
    
    func invoke(_ closure: (T) -> Void) {
        delegates.forEach { delegate in
            if let object = delegate.delegate as? T {
                closure(object)
            }
        }
    }
}

// Использование
let multicastDelegate = MulticastDelegate<NetworkServiceDelegate>()

4. Custom EventEmitter реализация

Можно создать собственную реализацию, похожую на JavaScript EventEmitter:

class EventEmitter<Event: Hashable> {
    private var listeners: [Event: [(Any) -> Void]] = [:]
    
    func on(_ event: Event, handler: @escaping (Any) -> Void) {
        listeners[event, default: []].append(handler)
    }
    
    func emit(_ event: Event, data: Any) {
        listeners[event]?.forEach { $0(data) }
    }
    
    func off(_ event: Event) {
        listeners.removeValue(forKey: event)
    }
}

// Пример использования
enum AppEvent {
    case userLoggedIn
    case dataUpdated
}

let emitter = EventEmitter<AppEvent>()
emitter.on(.userLoggedIn) { data in
    print("Событие: \(data)")
}

Сравнительная таблица абстракций

АбстракцияТипизацияМножественные подписчикиСложностьИспользование
NotificationCenterСлабая (строки)НизкаяГлобальные события приложения
CombineСильная (генерики)ВысокаяРеактивное программирование
DelegationСильная (протоколы)❌ (требует адаптера)СредняяКомпоненты UI, сервисы
Custom EmitterГибкаяЗависит от реализацииКастомные сценарии

Рекомендации по выбору:

  1. Для глобальных событий приложения — используйте NotificationCenter
  2. Для реактивных потоков данных — выбирайте Combine (для iOS 13+)
  3. Для коммуникации между компонентами — делегация с протоколами
  4. Для сложных кастомных сценариев — создавайте специализированные реализации

Ключевое отличие от JavaScript: в Swift все эти механизмы обеспечивают строгую типизацию и безопасность памяти через ARC, что предотвращает многие ошибки, характерные для динамических языков. Наиболее близким по духу является Combine Framework, который предоставляет полноценную реактивную систему с богатыми возможностями трансформации событий.

Какие абстракции в Swift похожи на event emitter? | PrepBro