如何从UpNextViewModel观察UpNextService属性并同步isShuffled状态?
如何让UpNextViewModel与UpNextService的isShuffled属性保持同步?
核心思路是让UpNextService作为唯一状态源,ViewModel不维护独立的isShuffled副本,而是通过计算属性直接代理到Service的对应属性,结合Swift的@Observable特性实现自动同步。
具体实现步骤
- 修改UpNextViewModel,用计算属性绑定Service的isShuffled
把ViewModel里的独立isShuffled字段替换为计算属性,读写操作直接转发给Service:
@Observable class UpNextViewModel { var repeatStatus: RepeatStatus = .none // 双向绑定Service的isShuffled,无本地状态冗余 var isShuffled: Bool { get { upNextService.isShuffled } set { upNextService.isShuffled = newValue } } let upNextService: UpNextService init(upNextService: UpNextService) { self.upNextService = upNextService } }
- 保持UpNextService的@Observable特性
原Service的@Observable修饰保留,确保当它的isShuffled变化时,所有依赖的ViewModel和视图都能收到更新通知:
@Observable class UpNextService { var isShuffled = false // 唯一可信的状态源 // 原有方法保持不变(修正异步方法的语法) func writeItems() async throws { let url = isShuffled ? FileManager.shuffledUpNextQueueURL : FileManager.originalUpNextQueueURL let (data, _) = try await URLSession.shared.data(from: url) // 写入逻辑 } func readItems() async throws -> [UpNextItem] { let url = isShuffled ? FileManager.shuffledUpNextQueueURL : FileManager.originalUpNextQueueURL let (data, _) = try await URLSession.shared.data(from: url) // 读取逻辑 return [] // 根据实际逻辑返回解析后的数据 } func removeItem(at index: Int) async throws { let url = isShuffled ? FileManager.shuffledUpNextQueueURL : FileManager.originalUpNextQueueURL let (data, _) = try await URLSession.shared.data(from: url) // 删除逻辑 } }
方案优势
- 无状态冗余:ViewModel不存独立的isShuffled值,完全依赖Service的唯一数据源,从根源避免不一致
- 自动同步:无论是通过ViewModel修改,还是其他直接操作Service的地方修改isShuffled,所有监听该属性的视图(不管关联哪个ViewModel)都会自动刷新
- 逻辑集中:状态变更的额外逻辑可以统一放在Service的
isShuffled的didSet中,比如:
@Observable class UpNextService { var isShuffled = false { didSet { if isShuffled != oldValue { // 状态变化时执行额外操作,比如日志记录、队列重排 } } } // ...原有方法 }
注意事项
- 确保所有ViewModel注入的是同一个UpNextService实例(可通过依赖注入容器、单例或SwiftUI环境变量传递),否则多个Service实例会导致状态分散
- ViewModel只负责转发状态和处理视图交互逻辑,业务逻辑尽量放在Service中,保持ViewModel轻量化
内容的提问来源于stack exchange,提问作者User95797654974
相关产品推荐
相关产品推荐

