SwiftUI:ObservedObject/ObservableObject 奇怪的行为
SwiftUI: ObservedObject/ObservableObject weird behavior
我最近在 SwiftUI
和 ObservedObject
/ObservableObject
中遇到了以下问题:
如果 ObservedObject
/ObservableObject
在视图中发布,body
属性 会按预期重新计算。
但是如果body
属性中有一个子View也有一个ObservedObject
,这个View,奇怪的是,不仅重新计算了body
属性 的子视图,但是整个 object
.
ObservedObject
的状态当然是迷失了子视图。
当然,您可以通过 .environmentObject()
向子视图添加 ObservableObject
来防止这种情况,但我认为这不是最好的解决方案,尤其是对于更复杂的视图层次结构。
这里有一个示例代码:
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
}
这里是示例代码 looks/works:
我意识到的最后一件奇怪的事情,只有当你使用 Observed Object 时才会出现这种情况。如果我将子视图 @ObservedObject var subViewModel: SubViewModel = SubViewModel()
替换为 @State var counter: Int = 0
,它再次正常工作并且状态被保留。
也许我错过了什么,但我真的很困惑。我非常感谢任何答案和解决方案。如果您还有其他问题,请随时发表评论,我会在 24 小时内回答(只要问题未解决)。
使用 @StateObject
声明您的 ViewModel。 @StateObject
不会为每个重新渲染的视图重新创建 more
struct SubView: View {
@StateObject var subViewModel: SubViewModel = SubViewModel() //<--- Here
var body: some View {
Button {
self.subViewModel.counter += 1
} label: {
Text(String(self.subViewModel.counter))
}
}
}
我找到了一个完美的解决方案:
在 iOS 14 (SwiftUI v2.0) 中将 @ObservedObject
替换为 @StateObject
(thx @Raja Kishan),或者您可以为视图创建一个包装器并模拟@StateObject
在 iOS 13 (SwiftUI v1.0) 中的行为:
struct SubViewWrapper: View {
@State var subViewModel: SubViewModel = SubViewModel()
var body: some View {
SubView(subViewModel: self.subViewModel)
}
}
然后在 ContentView 中使用 SubViewWrapper()
而不是 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()
}
}
}
我最近在 SwiftUI
和 ObservedObject
/ObservableObject
中遇到了以下问题:
如果 ObservedObject
/ObservableObject
在视图中发布,body
属性 会按预期重新计算。
但是如果body
属性中有一个子View也有一个ObservedObject
,这个View,奇怪的是,不仅重新计算了body
属性 的子视图,但是整个 object
.
ObservedObject
的状态当然是迷失了子视图。
当然,您可以通过 .environmentObject()
向子视图添加 ObservableObject
来防止这种情况,但我认为这不是最好的解决方案,尤其是对于更复杂的视图层次结构。
这里有一个示例代码:
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
}
这里是示例代码 looks/works:
我意识到的最后一件奇怪的事情,只有当你使用 Observed Object 时才会出现这种情况。如果我将子视图 @ObservedObject var subViewModel: SubViewModel = SubViewModel()
替换为 @State var counter: Int = 0
,它再次正常工作并且状态被保留。
也许我错过了什么,但我真的很困惑。我非常感谢任何答案和解决方案。如果您还有其他问题,请随时发表评论,我会在 24 小时内回答(只要问题未解决)。
使用 @StateObject
声明您的 ViewModel。 @StateObject
不会为每个重新渲染的视图重新创建 more
struct SubView: View {
@StateObject var subViewModel: SubViewModel = SubViewModel() //<--- Here
var body: some View {
Button {
self.subViewModel.counter += 1
} label: {
Text(String(self.subViewModel.counter))
}
}
}
我找到了一个完美的解决方案:
在 iOS 14 (SwiftUI v2.0) 中将 @ObservedObject
替换为 @StateObject
(thx @Raja Kishan),或者您可以为视图创建一个包装器并模拟@StateObject
在 iOS 13 (SwiftUI v1.0) 中的行为:
struct SubViewWrapper: View {
@State var subViewModel: SubViewModel = SubViewModel()
var body: some View {
SubView(subViewModel: self.subViewModel)
}
}
然后在 ContentView 中使用 SubViewWrapper()
而不是 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()
}
}
}