为什么我的Swift Combine Publisher没有发布更新?
问题原因
1. 错误使用Combine count() 操作符
Combine中的count()操作符用于统计上游Publisher历史发射的所有值的总数量,只有当上游Publisher发送finished完成事件时,才会输出最终统计结果。
你使用的@Published var listings对应的Publisher是无限流,只要ListingRepository实例未销毁就不会触发完成事件,且Firestore快照监听器是长期活跃的,会持续推送新的数组数据,因此count()永远不会触发输出,这就是Publisher没有回调、视图不更新的核心原因。
2. 重复实例化ListingRepository
你在MarketplaceViewModel和AccountViewModel中各自初始化了一个独立的ListingRepository实例,会同时启动两个完全无关的Firestore快照监听器,既浪费资源,也会导致两个页面的数据不一致。
解决方案
第一步:替换count()为map操作符
你需要的是每次listings数组更新时,获取当前数组的元素数量,直接用map操作符读取数组的count属性即可,修复后的AccountViewModel代码如下:
class AccountViewModel: ObservableObject { @Published var listingRepository = ListingRepository() @Published var numberOfListings: Int = 0 private var cancellables = Set<AnyCancellable>() init() { listingRepository .$listings .receive(on: RunLoop.main) // 替换原有count()为map取数组count .map { $0.count } .assign(to: \.numberOfListings, on: self) .store(in: &cancellables) } }
第二步:共享ListingRepository实例(可选但推荐)
将ListingRepository改为单例模式,避免重复启动监听器,修改代码如下:
class ListingRepository: ObservableObject { // 全局共享单例 static let shared = ListingRepository() let db = Firestore.firestore() @Published var listings = [Listing]() // 私有化初始化方法,禁止外部创建新实例 private init() { startSnapshotListener() } func startSnapshotListener() { // 原有监听器代码保持不变 } }
两个ViewModel中引用时统一使用ListingRepository.shared即可:
// MarketplaceViewModel和AccountViewModel中都改成这个写法 @Published var listingRepository = ListingRepository.shared
其他注意事项
检查修复代码中的语法错误:
AccountViewModel中多余的无意义@符号需要删除AccountView中Text组件的括号未闭合MarketplaceView中变量名拼写错误:marketplaceViewModel使用时写成了大小写不一致的marketPlaceViewModel
内容的提问来源于stack exchange,提问作者jonthornham
相关产品推荐
相关产品推荐

