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

Combine订阅异常:Core Data未读通知数无法实时更新UI

解决方案

问题的核心是原代码使用Just包装单次计数结果,导致仅在首次订阅时发送一次值,后续Core Data数据变更(如标记通知为已读)无法触发更新。以下是修正方案:

1. 改造Core Data计数Publisher

将单次计数改为监听上下文变化的持续Publisher,每次数据变更时重新计算未读数量:

public func fetchCountPublisher<T: PersistentModel>(_ type: T.Type, predicate: NSPredicate?) -> AnyPublisher<Int, Error> {
    let request = T.fetchRequest()
    request.predicate = predicate
    
    // 监听当前上下文的数据变更通知
    return NotificationCenter.default.publisher(
        for: NSManagedObjectContext.didChangeNotification,
        object: context
    )
    // 初始触发一次计数,保证启动时能获取初始值
    .prepend(())
    .flatMap { [weak self] _ -> AnyPublisher<Int, Error> in
        guard let self = self else {
            return Fail(error: NSError(
                domain: "Repository",
                code: -1,
                userInfo: [NSLocalizedDescriptionKey: "Repository已释放"]
            )).eraseToAnyPublisher()
        }
        do {
            let count = try self.context.count(for: request)
            return Just(count)
                .setFailureType(to: Error.self)
                .eraseToAnyPublisher()
        } catch {
            return Fail(error: error).eraseToAnyPublisher()
        }
    }
    // 确保在主线程发送结果,避免UI更新异常
    .receive(on: DispatchQueue.main)
    .eraseToAnyPublisher()
}

2. 修正未读判断逻辑

原代码中$0 > 1的判断不符合常规需求(只要有未读就应显示角标),建议修正:

var hasUnreadNotificationsPublisher: AnyPublisher<Bool, Error> {
    localNotificationsManager.hasUnreadNotifications()
        .map { $0 > 0 } // 只要存在未读通知就返回true
        .eraseToAnyPublisher()
}

3. 原有ViewModel/ViewController代码无需修改

ViewModel中对hasUnreadNotificationsPublisher的订阅、ViewController中对@Published状态的监听逻辑保持不变,上游Publisher持续发送新值时,UI会自动更新。

关键说明

  • 通过监听NSManagedObjectContext.didChangeNotification,能捕获所有当前上下文的Core Data数据变更(包括标记通知为已读的操作)
  • prepend(())确保首次订阅时立即获取初始计数
  • receive(on: DispatchQueue.main)保证UI更新在主线程执行,避免线程问题

内容的提问来源于stack exchange,提问作者Stefan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 05:07:38