SwiftUI 基于自定义协议实现泛型 ObservedObject 视图的正确写法
常见错误写法的根因
- 把模型类型换成
Any的写法会完全丢失类型上下文,既没法让@ObservedObject捕获到模型的状态变更,也没法直接调用模型上的业务方法,根本不具备可运行的基础 - 不添加任何约束的泛型
T写法过不了编译:@ObservedObject本身要求绑定的对象必须遵循ObservableObject协议,没有约束的泛型无法满足这个前置要求,会直接抛出编译错误
正确实现逻辑
你已经完成了统一业务协议抽象、两个模型分别遵循协议的前置工作,只需要给泛型参数叠加两层必要约束即可:
- 要求泛型类型遵循自定义的统一业务协议,保证视图内部可以正常调用所有通用的模型属性与方法
- 要求泛型类型遵循
ObservableObject协议,满足@ObservedObject的绑定要求,保证模型状态变更时可以正常触发视图刷新
参考实现代码
假设你自定义的统一业务协议为MyGenericModelProtocol,原有两个模型MyModel、SecondModel都已经遵循该协议并实现了ObservableObject协议一致性,改造后的视图代码如下:
// 直接在泛型声明位置添加双重约束 struct MyView<T: MyGenericModelProtocol & ObservableObject>: View { @ObservedObject private var myModel: T init(myModel: T) { self.myModel = myModel } // 原有视图渲染逻辑完全不需要改动 var body: some View { // 原视图内容直接复用即可 } }
如果觉得尖括号内堆叠太多约束可读性差,也可以把约束移到结构定义后的where子句中,两种写法效果完全等价:
struct MyView<T>: View where T: MyGenericModelProtocol, T: ObservableObject { @ObservedObject private var myModel: T init(myModel: T) { self.myModel = myModel } }
补充说明
- 这套实现完全保留编译期类型检查,不会像
Any类型那样出现运行时类型转换崩溃的问题 - 绑定状态监听的逻辑和最初绑定具体
MyModel类型的效果完全一致,模型属性变更时视图会正常触发重绘,没有功能损耗 - 外部调用时不需要写任何特殊的类型转换代码,直接传入任意一个遵循要求的模型实例即可,两种模型都可以正常渲染
内容的提问来源于stack exchange,提问作者Ronnie
相关产品推荐
相关产品推荐

