SwiftUI多ObservableObject架构实现手指计数器及联动逻辑问题
解决方案:主模型统一管控状态联动,彻底规避子模型依赖问题
核心思路:把所有业务逻辑全丢给主模型,子模型只负责存状态、发变更通知,完全做“哑巴”。既解决之前的无限循环问题,又能砍掉Combine监听的额外开销,还适配你提到的双视频同步场景。
1. 先定义纯哑子模型(左右手)
只负责存储计数,连加减逻辑都没有,就一个简单的设置方法:
import SwiftUI import Combine class Hand: ObservableObject { @Published var count: Int = 0 // 仅提供基础赋值,无任何业务逻辑 func setCount(_ value: Int) { count = value } }
2. 主模型:所有逻辑的中枢
主模型持有左右手实例,对外提供操作方法,进位逻辑全在这里处理,所有状态变更都由它主动触发:
class FingerCounterModel: ObservableObject { let leftHand = Hand() let rightHand = Hand() // 左手加1,主模型统一处理进位 func incrementLeftHand() { let newLeft = leftHand.count + 1 if newLeft >= 5 { leftHand.setCount(0) rightHand.setCount(rightHand.count + 1) } else { leftHand.setCount(newLeft) } } // 右手加1(按需实现) func incrementRightHand() { rightHand.setCount(rightHand.count + 1) } // 重置所有计数 func reset() { leftHand.setCount(0) rightHand.setCount(0) } }
3. SwiftUI视图:纯展示+触发操作
视图只负责绑定状态、把用户操作转递给主模型,半毛钱逻辑都没有:
struct FingerCounterView: View { @StateObject private var model = FingerCounterModel() var body: some View { VStack(spacing: 30) { HandView(title: "左手", count: model.leftHand.count, onTap: model.incrementLeftHand) HandView(title: "右手", count: model.rightHand.count, onTap: model.incrementRightHand) Button("重置") { model.reset() } .buttonStyle(.borderedProminent) } .padding() } } // 完全哑的子视图,只做展示和事件传递 struct HandView: View { let title: String let count: Int let onTap: () -> Void var body: some View { VStack { Text(title) .font(.title) Text("\(count)") .font(.largeTitle) .fontWeight(.bold) Button("加1") { onTap() } .buttonStyle(.bordered) } .padding() .border(.gray, width: 2) .cornerRadius(8) } }
为什么这方案能解决问题?
- 彻底消除无限循环:没有监听子模型的
objectWillChange再修改状态的逻辑,所有变更都是主模型主动触发,不会出现循环触发的死锁。 - 效率拉满:砍掉了Combine订阅分发的额外开销,状态变更路径直接明了。
- 严格符合哑组件设计:Hand模型和HandView完全无业务逻辑,所有规则都集中在主模型,后续改进位规则(比如改成满10进位),只需要改主模型的方法就行。
适配双视频同步场景的迁移思路
把这套逻辑直接套过去就行:
- 把左右手换成两个视频的状态模型(比如
VideoPlayerState,包含currentTime、isPlaying等属性,纯哑模型) - 主模型(比如
SyncVideoModel)持有两个VideoPlayerState实例,对外提供同步拖动、同步播放的方法,在方法里处理两个视频的状态联动(比如拖动A视频进度时,同步修改B视频的进度) - 视频播放器视图只负责绑定状态、触发主模型的操作,完全不碰同步逻辑
内容的提问来源于stack exchange,提问作者chris P
相关产品推荐
相关产品推荐

