You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 12:45:32