如何使用Combine与Swift创建并发送自定义事件?
实现多订阅者事件系统(基于Combine)
你可以直接利用Swift官方的Combine框架实现需求,完全不需要手动编写Subscription、Publisher这类底层代码。下面是具体实现方案:
1. 定义事件枚举
先统一管理需要监听的事件类型,方便订阅时精准指定:
import Combine // 假设Item是你的自定义数据类型 class Item {} enum ObservedEvent { case listChanged(addingItems: [Item], removingItems: [Item]) // 扩展支持Void事件 case someVoidEvent }
2. 实现被观察类
用PassthroughSubject作为事件发布源(专门用于发送一次性事件,无需保存当前值),同时封装事件发送逻辑,避免无意义的重复推送:
class SomeObservedClass: ObservableObject { // 内部事件发送源,对外隐藏实现细节 private let eventSubject = PassthroughSubject<ObservedEvent, Never>() // 对外暴露可订阅的Publisher var eventPublisher: AnyPublisher<ObservedEvent, Never> { eventSubject.eraseToAnyPublisher() } // 示例:修改列表并触发事件的方法 func updateList(add newItems: [Item], remove oldItems: [Item]) { // 先执行实际的列表修改逻辑... // 仅当数据真的有变化时发送事件,避免重复推送 if !newItems.isEmpty || !oldItems.isEmpty { eventSubject.send(.listChanged(addingItems: newItems, removingItems: oldItems)) } } // 示例:触发Void事件的方法 func triggerVoidAction() { eventSubject.send(.someVoidEvent) } }
3. 实现订阅者逻辑
通过eventPublisher订阅目标事件,用filter筛选关心的事件类型,map提取参数:
class SomeListener1 { private var cancellables = Set<AnyCancellable>() var observedClass: SomeObservedClass init() { observedClass = SomeObservedClass() // 订阅列表变更事件 observedClass.eventPublisher .filter { event in guard case .listChanged = event else { return false } return true } .map { event -> ([Item], [Item]) in guard case .listChanged(addingItems: let add, removingItems: let remove) = event else { return ([], []) } return (add, remove) } .sink { addingItems, removingItems in // 处理数据变更逻辑 print("新增\(addingItems.count)个元素,移除\(removingItems.count)个元素") } .store(in: &cancellables) // 订阅Void事件 observedClass.eventPublisher .filter { $0 == .someVoidEvent } .sink { _ in // 处理Void事件逻辑 print("触发了Void事件") } .store(in: &cancellables) } }
4. 简化订阅语法(可选)
如果觉得每次filter+map太繁琐,可以给AnyPublisher扩展专用订阅方法,让代码更贴近你的伪代码写法:
extension AnyPublisher where Output == ObservedEvent, Failure == Never { // 针对列表变更事件的简化订阅 func sink(for event: ObservedEvent, receiveChanges: @escaping ([Item], [Item]) -> Void) -> AnyCancellable { self .filter { $0 == event } .map { event -> ([Item], [Item]) in guard case .listChanged(addingItems: let add, removingItems: let remove) = event else { return ([], []) } return (add, remove) } .sink(receiveValue: receiveChanges) } // 针对Void事件的简化订阅 func sink(for event: ObservedEvent, receiveVoid: @escaping () -> Void) -> AnyCancellable { self .filter { $0 == event } .sink(receiveValue: { _ in receiveVoid() }) } }
简化后的订阅代码:
class SomeListener1 { private var cancellables = Set<AnyCancellable>() var observedClass: SomeObservedClass init() { observedClass = SomeObservedClass() // 订阅列表变更事件 observedClass.eventPublisher .sink(for: .listChanged) { addingItems, removingItems in // 处理数据 } .store(in: &cancellables) // 订阅Void事件 observedClass.eventPublisher .sink(for: .someVoidEvent) { // 处理Void事件 } .store(in: &cancellables) } }
核心优势
- 基于官方Combine框架,无需手动实现订阅发布底层逻辑
- 可灵活控制事件发送时机,避免重复推送无意义的相同事件
- 支持多订阅者独立订阅各自关心的事件
- 同时兼容带参数事件和Void事件
内容的提问来源于stack exchange,提问作者bodich
相关产品推荐
相关产品推荐

