SwiftUI 视图不会更新具有子类的已发布对象
SwiftUI view does not update for Published objects with subclasses
因为我的实际代码有点复杂,这里有一个简化的 class 结构,我可以用它重现同样的意外行为。
这是我子class:
的基础数据对象
class People: Identifiable {
var name: String
required init(name: String) {
self.name = name
}
}
class Men: People {
}
然后我使用另一个 class,它也充当 superclass,但也使用通用类型 People
。
class SuperMankind<PlayerType: People> {
var people: [PlayerType] = []
}
class Mankind: SuperMankind<Men> {
}
现在我想在我的 ViewModel 中使用这个 Mankind
subclass,它是一个 ObservableObject。
class ViewModel: ObservableObject {
@Published var mankind: Mankind
init(_ m: Mankind) {
mankind = m
}
}
struct TestView: View {
@StateObject var viewModel = ViewModel(Mankind())
var body: some View {
VStack {
Button("Add") {
viewModel.mankind.people.append(Men(name: Int.random(in: 0...1000).description))
}
List {
ForEach(viewModel.mankind.people) {
Text([=12=].name)
}
}
}
}
}
但我不知道为什么单击添加按钮后我的视图不会更新。我发现如果我将以下代码添加到我的按钮操作中,视图就会更新。但是我认为不需要手动调用,所以我认为我做错了什么。
viewModel.objectWillChange.send()
ObservableObject
.
我稍微修改了你的代码,它起作用了:
protocol SuperMankind {
associatedtype PlayerType
var people: [PlayerType] { get set }
}
struct Mankind: SuperMankind {
var people: [Men] = []
}
Screenshot here
关于您的解决方案(因为我无法发表评论):
Array<Men>
是一个结构,尽管数组包含 class 引用。这就是为什么您的代码现在可以工作的原因,就像之前您直接在 ObservableObject
中持有对 class 的引用(因此没有更新视图)。
@SwiftSharp 感谢您的回答,associatedType
我没有想到这一点。但是 @Published
字段需要是结构是不正确的考虑这个解决方案,我现在会选择它,因为我不想让我的所有功能都发生变化。
class People: Identifiable {
var name: String
required init(name: String) {
self.name = name
}
}
class Men: People {
}
class SuperMankind<PlayerType: People>: ObservableObject {
@Published var people: [PlayerType] = []
}
class Mankind: SuperMankind<Men> {
}
struct TestView: View {
@StateObject var viewModel = Mankind()
var body: some View {
VStack {
Button("Add") {
viewModel.people.append(Men(name: Int.random(in: 0...1000).description))
}
List {
ForEach(viewModel.people) {
Text([=10=].name)
}
}
}
}
}
我的问题是 ViewModel
class 不是必需的,而且我的 superclass 包含 people 数组不是 ObervableObject。
编辑 仅在此处完成:
这也将解决我最初的代码问题,使用 ViewModel class,但不是 subclassing ObservableObject 我会从 Mankind
subclass,它已经符合通过 subclassing SuperMankind:
到 ObservableObject
class ViewModel: Mankind {
}
因为我的实际代码有点复杂,这里有一个简化的 class 结构,我可以用它重现同样的意外行为。
这是我子class:
的基础数据对象class People: Identifiable {
var name: String
required init(name: String) {
self.name = name
}
}
class Men: People {
}
然后我使用另一个 class,它也充当 superclass,但也使用通用类型 People
。
class SuperMankind<PlayerType: People> {
var people: [PlayerType] = []
}
class Mankind: SuperMankind<Men> {
}
现在我想在我的 ViewModel 中使用这个 Mankind
subclass,它是一个 ObservableObject。
class ViewModel: ObservableObject {
@Published var mankind: Mankind
init(_ m: Mankind) {
mankind = m
}
}
struct TestView: View {
@StateObject var viewModel = ViewModel(Mankind())
var body: some View {
VStack {
Button("Add") {
viewModel.mankind.people.append(Men(name: Int.random(in: 0...1000).description))
}
List {
ForEach(viewModel.mankind.people) {
Text([=12=].name)
}
}
}
}
}
但我不知道为什么单击添加按钮后我的视图不会更新。我发现如果我将以下代码添加到我的按钮操作中,视图就会更新。但是我认为不需要手动调用,所以我认为我做错了什么。
viewModel.objectWillChange.send()
ObservableObject
我稍微修改了你的代码,它起作用了:
protocol SuperMankind {
associatedtype PlayerType
var people: [PlayerType] { get set }
}
struct Mankind: SuperMankind {
var people: [Men] = []
}
Screenshot here
关于您的解决方案(因为我无法发表评论):
Array<Men>
是一个结构,尽管数组包含 class 引用。这就是为什么您的代码现在可以工作的原因,就像之前您直接在 ObservableObject
中持有对 class 的引用(因此没有更新视图)。
@SwiftSharp 感谢您的回答,associatedType
我没有想到这一点。但是 @Published
字段需要是结构是不正确的考虑这个解决方案,我现在会选择它,因为我不想让我的所有功能都发生变化。
class People: Identifiable {
var name: String
required init(name: String) {
self.name = name
}
}
class Men: People {
}
class SuperMankind<PlayerType: People>: ObservableObject {
@Published var people: [PlayerType] = []
}
class Mankind: SuperMankind<Men> {
}
struct TestView: View {
@StateObject var viewModel = Mankind()
var body: some View {
VStack {
Button("Add") {
viewModel.people.append(Men(name: Int.random(in: 0...1000).description))
}
List {
ForEach(viewModel.people) {
Text([=10=].name)
}
}
}
}
}
我的问题是 ViewModel
class 不是必需的,而且我的 superclass 包含 people 数组不是 ObervableObject。
编辑 仅在此处完成:
这也将解决我最初的代码问题,使用 ViewModel class,但不是 subclassing ObservableObject 我会从 Mankind
subclass,它已经符合通过 subclassing SuperMankind:
class ViewModel: Mankind {
}