SwiftUI:@ObservedObject 与 @StateObject 子视图性能?
Posted
技术标签:
【中文标题】SwiftUI:@ObservedObject 与 @StateObject 子视图性能?【英文标题】:SwiftUI: @ObservedObject vs @StateObject child view performance? 【发布时间】:2021-07-23 20:35:03 【问题描述】:我有以下看法:
struct Menu: View
let sctions:[TestSection] = [
TestSection(id: 0, name: "One", items: [
ListItem(id: 0, name: "1"),
ListItem(id: 1, name: "2"),
ListItem(id: 2, name: "3"),
ListItem(id: 3, name: "4")
]),
TestSection(id: 1, name: "Two", items: [
ListItem(id: 4, name: "4"),
ListItem(id: 5, name: "5"),
ListItem(id: 6, name: "6"),
ListItem(id: 7, name: "7")
]),
TestSection(id: 2, name: "Three", items: [
ListItem(id: 8, name: "8"),
ListItem(id: 9, name: "9"),
])
]
var body: some View
NavigationView
List
ForEach(sctions) section in
Section(header: Text(section.name))
ForEach(section.items) item in
TestCell(item: item)
.listStyle(.plain)
.navigationBarTitle("Title")
struct TestCell: View
@ObservedObject private var model:ItemModel
let item:ListItem
init(item:ListItem)
self.item = item
self.model = ItemModel(itemId:item.id)
var body: some View
Text("item: \(item.name)")
class ItemModel:ObservableObject
@Published var someProperty:Int
let itemId:Int
init(itemId:Int)
self.itemId = itemId
self.someProperty = 0
我正在尝试从模型层的角度决定如何在 SwiftUI 中处理子视图。
一个选项是子视图中的@ObservedObject
。父级创建模型并将其设置在子级上,或者父级在子级上传递一个属性,然后允许子级在其初始化程序中初始化模型:
init(item:ListItem)
self.item = item
self.model = ItemModel(itemId:item.id). // <<---- HERE
然后看看这个,我想知道这是否不如在子视图中使用@StateObject
来管理其模型的生命周期。
然后我尝试了这个:
struct TestCell: View
@StateObject var model = ItemModel() // <<-- error "Missing argument for parameter 'itemId' in call"
let item:ListItem
var body: some View
Text("item: \(item.name)")
其中,显然显示了错误:
我不确定在使用@StateObject
方法时如何在TestCell
中初始化ItemModel
。
我的问题是:
在这种类型的场景中,我希望每个单元都有自己的模型(以处理与模型相关的逻辑,例如进行网络调用、更新模型层等...)我应该创建模型,因为我在创建单元格期间实例化父级中的单元格,并将其设置在单元格上 (@ObservedObject
)?
或者单元格是否应该为其模型使用@StateObject
,如果是,我如何让模型在需要参数时正确初始化自己,例如let itemId:Int
?
【问题讨论】:
【参考方案1】:不推荐您的第一个选项,因为
init(item:ListItem)
self.item = item
self.model = ItemModel(itemId:item.id). // <<---- HERE
在视图中创建观察对象是不安全的
https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app
您会在 SO 中找到许多关于 View
s 不可靠的问题。您还会发现那些告诉人们这样做的人,但您会发现它存在问题。
如果您使用@StateObject var model: ItemModel = ItemModel()
,根据 Apple 的规定,这是在 View
中创建 ObservableObject
的唯一例外
然后切换
let itemId:Int
在您的ItemModel
中
var itemId:Int = 0
然后在TestCell
中添加到最外层的View
.onAppear()
model.itemId = item.id
或者根据您的 ParentView 及其 ViewModel,您可以在 class
ViewModel 中创建 ObservableObject
s 并将其作为参数传递给
@ObservedObject private var model:ItemModel
重要的是,解决方法考虑到不应在View
中创建ObservableObject
,@StateObject
除外。 SwiftUI 保留在认为有必要时重新创建任何View
的权利。
【讨论】:
那么,@StateObject 根本不被视为驱动单元的选项? 不,StateObject 是最好的选择。当我提供选项时,我不知何故跳过了这一点。 StateObject 是在 View 中初始化 ObservableObject 的唯一保存方法。 好的,所以如果我在视图中初始化对象,那么 StateObject 是首选方式。如果我想从父视图传递它,那么 ObservedObject 是要走的路吗? 这取决于我在大多数情况下更喜欢 EnvironmentObject,但其他人更喜欢 ObservedObject。以上是关于SwiftUI:@ObservedObject 与 @StateObject 子视图性能?的主要内容,如果未能解决你的问题,请参考以下文章
极简示例揭示 SwiftUI 中 @ObservedObject 与 @StateObject 状态的关键区别
UITextView 的 SwiftUI Wrapper 未更新 ObservedObject
SwiftUI - 如何使用 ObservedObject 或 EnvironmentObject 存储 GeometryReader 数据?
通用结构 'ObservedObject' 要求 'Video' 符合 SwiftUI 中的 'ObservableObject'