SwiftUI 视图不会为具有子类的已发布对象更新

Posted

技术标签:

【中文标题】SwiftUI 视图不会为具有子类的已发布对象更新【英文标题】:SwiftUI view does not update for Published objects with subclasses 【发布时间】:2022-01-05 01:20:51 【问题描述】:

因为我的实际代码有点复杂,这里有一个简化的类结构,我可以用它重现相同的意外行为。

这是我的子类的基础数据对象:

class People: Identifiable 
    var name: String
    
    required init(name: String) 
        self.name = name
    


class Men: People 
    

然后我使用另一个类,它也充当超类,但也使用People 的泛型类型。

class SuperMankind<PlayerType: People> 
    var people: [PlayerType] = []


class Mankind: SuperMankind<Men> 


现在我想在我的 ViewModel 中使用这个 Mankind 子类,它是一个 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($0.name)
                
            
        
    

但是如果我单击添加按钮,我的视图不会更新,我不知道为什么。我发现如果我将以下代码添加到我的按钮操作中,视图就会更新。但在我看来,这个手动调用不应该是必要的,所以我认为我做错了什么。

viewModel.objectWillChange.send()

【问题讨论】:

【参考方案1】:

@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($0.name)
                
            
        
    

我的问题是 ViewModel 类不是必需的,而且我的包含人员数组的超类不是 ObervableObject。

编辑在这里完成: 这也将解决我的初始代码问题,使用 ViewModel 类,但不是子类化 ObservableObject,我将从 Mankind 子类化,它已经通过继承 SuperMankind 符合 ObservableObject:

class ViewModel: Mankind 
    

【讨论】:

【参考方案2】:

ObservableObjectrequires that its fields are structs, not classes.

我稍微修改了你的代码,它起作用了:

protocol SuperMankind 
    associatedtype PlayerType
    var people: [PlayerType]  get set 


struct Mankind: SuperMankind 
    var people: [Men] = []

Screenshot here

您的解决方案(因为我无法发表评论):

Array&lt;Men&gt; 是一个结构,尽管数组包含类引用。这就是为什么您的代码现在可以正常工作的原因,就像之前您在 ObservableObject 中直接持有对类的引用一样(因此没有更新视图)。

【讨论】:

特别是因为您帮助我了解了问题的根本原因。 只是出于兴趣,您宁愿选择没有 viewModel 的我的解决方案,还是将我编辑的方法与 viewModel 类一起使用? @AlexB 我会说你没有 ViewModel 类的方法会是两者中更好的方法,尽管我不会尝试使用类,除非我绝对需要,尤其是在使用 SwiftUI 时。

以上是关于SwiftUI 视图不会为具有子类的已发布对象更新的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 不会将状态更新为 @ObservedObject cameraViewModel 对象

SwiftUI:具有计时器样式的文本在提供的日期更改后不会更新

SwiftUI:如何使用位置管理器类的已发布属性更新一个类(ObservableObject)的已发布属性?

SwiftUI:如果 @ObservedObject 是 UIViewController 的子类,则不会重新加载视图内容。这是一个错误还是我错过了啥?

SwiftUI - 环境对象未更新 UI

嵌套 ObservedObject 中的更改不会更新 UI