1

SwiftUI我最近在ObservedObject/中遇到了以下问题ObservableObject

如果ObservedObject/ObservableObject在视图中发布,body则按预期重新计算属性。

但是如果body属性中有一个子 View 也有一个ObservedObject,那么奇怪的是,这个 View 不仅重新计算body了子 View 的属性,而且重新计算了整个object.

状态当然ObservedObject 从子视图中丢失。

当然,您可以通过添加ObservableObject到子视图来防止这种情况.environmentObject(),但我认为这不是最好的解决方案,尤其是对于更复杂的视图层次结构。

这是一个示例代码:

struct ContentView: View {
    
    @ObservedObject var contentViewModel: ContentViewModel = ContentViewModel()
    
    var body: some View {
        VStack {
            Button {
                self.contentViewModel.counter += 1
            } label: {
                Text(String(self.contentViewModel.counter))
            }
            
            SubView()
        }
    }
}
class ContentViewModel: ObservableObject {
    @Published var counter: Int = 0
}

和子视图:

struct SubView: View {
    
    @ObservedObject var subViewModel: SubViewModel = SubViewModel()
    
    
    var body: some View {
        Button {
            self.subViewModel.counter += 1
        } label: {
            Text(String(self.subViewModel.counter))
        }
    }
}
class SubViewModel: ObservableObject {
    @Published var counter: Int = 0
}

以及示例代码的外观/工作方式:

预览

我意识到的最后一件奇怪的事情,只有当你使用 Observed Object 时才会出现这种情况。如果我将在子视图中@ObservedObject var subViewModel: SubViewModel = SubViewModel()替换@State var counter: Int = 0它,它会再次正常工作并保留状态。

也许我错过了一些东西,但我真的很困惑。我非常感谢任何答案和解决方案。如果您还有其他问题可以发表评论,我会在 24 小时内回复(只要问题是开放的)。

4

2 回答 2

3

用 . 声明你的 ViewModel @StateObject@StateObject不会为每个视图重新创建重新渲染更多

struct SubView: View {
    @StateObject var subViewModel: SubViewModel = SubViewModel() //<--- Here
    
    var body: some View {
        Button {
            self.subViewModel.counter += 1
        } label: {
            Text(String(self.subViewModel.counter))
        }
    }
}
于 2021-02-03T08:29:47.353 回答
0

我找到了一个完美的解决方案:

您可以在 iOS 14 (SwiftUI v2.0) 中将其替换为@ObservedObject( @StateObjectthx @Raja Kishan),也可以为 View 创建一个 Wrapper 并模拟@StateObjectiOS 13 (SwiftUI v1.0) 中的行为:

struct SubViewWrapper: View {
    @State var subViewModel: SubViewModel = SubViewModel()

    var body: some View {
        SubView(subViewModel: self.subViewModel)
    }
}

然后SubViewWrapper()在 ContentView 中使用而不是SubView()

struct ContentView: View {
    
    @ObservedObject var contentViewModel: ContentViewModel = ContentViewModel()
    
    var body: some View {
        VStack {
            Button {
                self.contentViewModel.counter += 1
            } label: {
                Text(String(self.contentViewModel.counter))
            }
            
            SubViewWrapper()
        }
    }
}
于 2021-02-03T09:29:19.843 回答