SwiftUI - 解释 View 中数据刷新时 EnvironmentObject 与 ObservableObject 行为的差异

Posted

技术标签:

【中文标题】SwiftUI - 解释 View 中数据刷新时 EnvironmentObject 与 ObservableObject 行为的差异【英文标题】:SwiftUI - explain difference in EnvironmentObject vs ObservableObject behavior on data refresh in View 【发布时间】:2021-03-11 18:37:25 【问题描述】:

我正在构建一个类似 Instagram 的应用程序,我注意到如果视图使用 ObservableObject (viewModel.posts) 从 Firestore 访问数据,则刷新数据时视图会闪烁。例如如果按赞按钮或添加了新帖子。

当视图使用 EnvironmentObject (session.posts) 从 Firestore 访问数据时,更新会顺利进行,不会出现任何闪烁。谁能解释为什么会这样?

这是 ObservableObject 的代码:

import SwiftUI
import Firebase

class PostViewModel: ObservableObject 
    @Published var posts = [Post]()
    
    init() 

        fetchPosts()
    
    
    func fetchPosts() 

        COLLECTION_POSTS
            .order(by: "timeStamp", descending: true)
            .addSnapshotListener  querySnapshot, error in
                guard let documents = querySnapshot?.documents else 
                    print("Error fetching Request documents: \(error!)")
                    return
                
                self.posts.removeAll(keepingCapacity: false)

                for doc in documents 
                    let mappedDoc = Post(dictionary: doc.data())
                    self.posts.append((mappedDoc!))
                
                return
            
    

这里是 EnvironmentObject 的代码:

import Foundation
import Firebase

class FirebaseSession: ObservableObject 
    @Published var posts: [Post] = []


extension FirebaseSession 

    func listenerPosts() 
        
        COLLECTION_POSTS
            .order(by: "timeStamp", descending: true)
            .addSnapshotListener  querySnapshot, error in
                guard let documents = querySnapshot?.documents else 
                    print("Error fetching Request documents: \(error!)")
                    return
                
                self.posts.removeAll(keepingCapacity: false)
                
                for doc in documents 
                    let mappedDoc = Post(dictionary: doc.data())
                    self.posts.append((mappedDoc!))
                
                return
            
    

【问题讨论】:

当您在视图中使用 ObservableObject 时,您是使用它作为@ObservedObject 还是@StateObject? 您是如何设法将@Published 放入扩展程序的?你确定你没有遗漏任何重要的代码吗? @jnpdx,我在视图中使用的是 ObservedObject,而不是 StateObject。 @pawello2222 - 你是对的,我已经在 FirebaseSession 类中发布了。 我认为你是对的,似乎 ObservableObject 的视图在每次发生变化时都在运行init(),这意味着在检测到变化后视图被清除并重绘。我发现这两篇解释差异的文章希望它们可以帮助您理解article1article2 【参考方案1】:

已解决:使用 ObservedObject 重绘 View,使用 StateObject 解决了问题

【讨论】:

以上是关于SwiftUI - 解释 View 中数据刷新时 EnvironmentObject 与 ObservableObject 行为的差异的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 后台刷新多个 Section 导致 global index in collection view 与实际不匹配问题的解决

SwiftUI 如何快速识别视图(View)界面的刷新是由哪个状态的改变导致的?

SwiftUI 如何快速识别视图(View)界面的刷新是由哪个状态的改变导致的?

SwiftUI button 与sheet的使用

在我切换到浅色或深色模式之前,SwiftUI View 不会显示数据

SwiftUI @AppStorage 不在函数中刷新