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

RxSwift:UITabBarController中UICollectionView添加收藏后不更新问题

解决UITabBarController中收藏列表UICollectionView不更新的问题

这个问题的核心在于你的FavouriteViewModel没有监听Realm数据库的实时变化,仅在手动调用fetchDateFromDb时才会推送数据。当第一个VC修改数据库后,第二个VC的ViewModel没有感知到这个变化,所以UICollectionView不会更新。下面是具体的解决方案:

1. 改用Realm的实时通知机制监听数据变化

Realm本身提供了对查询结果的实时监听能力,我们可以利用这个特性在数据库数据变化时自动推送新的列表数据。同时把PublishSubject换成BehaviorSubject(或者RxCocoa的PublishRelay),这样新订阅的观察者能立即拿到当前最新的数据,而不是只有订阅后的新事件。

修改FavouriteViewModel代码

import RealmSwift
import RxSwift
import RxCocoa

class FavouriteViewModel {
    // 用BehaviorSubject保存当前文章列表,初始值为空数组
    let articlesSubject: BehaviorSubject<[ArticleModel]> = BehaviorSubject(value: [])
    
    // Realm通知的Token,用于在销毁时移除监听
    private var notificationToken: NotificationToken?
    private let disposeBag = DisposeBag()
    
    init() {
        // 初始化时就启动Realm监听
        setupRealmNotification()
        // 先获取一次初始数据
        fetchDateFromDb()
    }
    
    deinit {
        // 移除Realm通知监听,避免内存泄漏
        notificationToken?.invalidate()
    }
    
    func fetchDateFromDb(){
        let articleList = DatabaseManager.shared.getAllArticle().toArray()
        articlesSubject.onNext(articleList)
    }
    
    private func setupRealmNotification() {
        // 获取Realm的查询结果(注意Realm的Results是实时的)
        let results = DatabaseManager.shared.getAllArticle()
        
        // 监听查询结果的变化
        notificationToken = results.observe { [weak self] change in
            guard let self = self else { return }
            
            switch change {
            case .initial(let results):
                // 初始加载数据(可选,因为fetchDateFromDb已经调用过)
                self.articlesSubject.onNext(results.toArray())
            case .update(let results, _, _, _):
                // 数据发生更新,推送新的列表
                self.articlesSubject.onNext(results.toArray())
            case .error(let error):
                // 处理监听错误
                print("Realm通知错误: \(error.localizedDescription)")
            }
        }
    }
}

2. 确保FavouriteVC的绑定逻辑兼容BehaviorSubject

你的setupBinds代码不需要做太多修改,因为BehaviorSubject会在订阅时自动发送当前的最新值,确保UICollectionView能加载初始数据:

private func setupBinds(){
    self.favArticleCollectionView.register(UINib(nibName: "PreviewItemVCell", bundle: nil), forCellWithReuseIdentifier: PreviewItemVCell.identifier)
    viewModel
        .articlesSubject
        .observeOn(MainScheduler.instance)
        .bind(to: self.favArticleCollectionView.rx.items(cellIdentifier: PreviewItemVCell.identifier, cellType: PreviewItemVCell.self)) { (item, article,cell) in
            cell.article = article
        }.disposed(by: disposeBag)
}

3. 可选补充:在viewWillAppear时手动刷新

为了确保用户切回收藏页面时数据绝对最新,可以在FavouriteVC的viewWillAppear中手动调用一次数据刷新:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    viewModel.fetchDateFromDb()
}

为什么原来的代码无法更新?

  • 你使用的PublishSubject是“冷”的,只有在调用onNext时才会发送数据,而数据库变化时没有触发这个操作。
  • FavouriteViewModel没有监听Realm的实时变化,无法感知第一个VC对数据库的修改,自然不会主动推送新数据给UICollectionView。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:13:09