SwiftUI 创建遵循ObservableObject的类数组属性及StateObject报错解决
错误原因
@StateObject是SwiftUI专门用来包装遵循ObservableObject协议的类实例的属性包装器,你当前直接把排序后的[Project]数组(值类型,不遵守ObservableObject协议)赋值给它,自然会触发类型不匹配的报错。
解决方案
方案1:视图内动态排序(最简便,适合小数据量场景)
不需要改动现有模型层代码,仅调整视图层实现即可:
- 用
@StateObject绑定本身就遵守ObservableObject协议的SQS_Table实例:
// 替换原来的错误行 @StateObject private var projectsTbl = SQS_Table<Project>(...)
- 新增视图计算属性,自动返回排序后的数组,原数组变更时会自动重新计算:
private var sortedItems: [Project] { projectsTbl.records.sorted { $0.__idx < $1.__idx } }
- 修改
ForEach数据源为这个计算属性:
// 注意原代码中的id参数\.__id是笔误,你的模型里只有__idx属性,需要修正 ForEach(sortedItems, id: \.__idx) { proj in ProjectElement(project: proj) }
方案2:模型层内置排序逻辑(适合大数据量、高频排序场景)
如果排序操作执行频繁,不想每次视图刷新都重新排序,可以把排序逻辑封装到SQS_Table内部,避免重复计算:
- 改造
SQS_Table类,新增自动更新的排序数组属性:
import Combine // 需要导入Combine框架 class SQS_Table<RecordType: SQS_Record>: ObservableObject { @Published var records = [RecordType]() @Published var sortedRecords: [RecordType] = [] private var cancellable = Set<AnyCancellable>() init(/* 原有参数 */) { // 监听records变更,自动重新排序赋值 $records .map { $0.sorted { $0.__idx < $1.__idx } } .assign(to: \.sortedRecords, on: self) .store(in: &cancellable) // 原有初始化逻辑保持不变 } // 原有其他逻辑保持不变 var rcount: Int { records.count } subscript (index: Int) -> RecordType { get { records[index] } set { records[index] = newValue } } }
- 视图层直接使用内置的排序数组即可:
@StateObject private var projectsTbl = SQS_Table<Project>(...) var body: some View { NavigationView { List { ForEach(projectsTbl.sortedRecords, id: \.__idx) { proj in ProjectElement(project: proj) } .onMove(perform: moveItem ) .onDelete(perform: delItem ) } } }
额外注意点
如果projectsTbl是从上级视图传入的,不要用@StateObject,换成@ObservedObject即可,避免重复创建实例导致数据不同步。
内容的提问来源于stack exchange,提问作者Alex778801
相关产品推荐
相关产品推荐

