SwiftUI:@ObservedObject 与 @StateObject 子视图性能?

时间:2021-07-23 20:35:03

标签: swiftui

我有以下观点:

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)")


    }

}

哪个,显然显示错误:

enter image description here

我不确定在使用 ItemModel 方法时如何在 TestCell 中初始化 @StateObject

我的问题是:

在这种类型的场景中,我希望每个单元格都有自己的模型(处理模型相关的逻辑,如进行网络调用、更新模型层等...)我应该创建当我在创建单元格期间在父级中实例化单元格并将其设置在单元格 (@ObservedObject) 上时建模?

或者一个单元应该使用 @StateObject 作为它的模型,如果是这样,我如何让模型在需要参数时正确地初始化自己,例如 let itemId:Int

1 个答案:

答案 0 :(得分:0)

不推荐您的第一个选项,因为

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 不可靠的问题。你还会发现那些告诉人们这样做的人,但你会发现它有问题。

如果您使用 @StateObject var model: ItemModel = ItemModel(),这是 Apple 在 ObservableObject 中创建 View 的唯一例外

然后切换

let itemId:Int 

在您的 ItemModel

var itemId:Int = 0

然后在 TestCell 中添加到最外面的 View

.onAppear(){
    model.itemId = item.id
}

或者根据您的 ParentView 及其 ViewModel,您可以在 ObservableObject ViewModel 中创建 class 并将其作为参数传递给

@ObservedObject private var model:ItemModel

重要的是,解决方法考虑到不应在 ObservableObject 中创建 View@StateObject 除外。 SwiftUI 保留在认为有必要时重新创建任何 View 的权利。