【问题标题】:UI changes with ObservableObject just after switching tabs切换选项卡后 UI 会随 ObservableObject 发生变化
【发布时间】:2020-03-17 21:59:03
【问题描述】:

我有一个ObservableObject,用于在从服务器发送新数据时更新我的​​ UI(一个包含自定义结构数组的类)。

由于某种原因,发送数据时,ContentViewbody 被调用,但数据没有改变。我什至添加了一个print 语句来检查数组包含的数据是否正确。

当我尝试切换到 TabView 上的另一个选项卡,然后切换回主视图时,UI确实会更新。有人知道为什么 UI 会在我切换标签时更新,尽管 body 会在数据更改时被召回以更新 UI?

主视图

struct HomeView: View {
    @ObservedObject private var fbData = firebaseData

    var body: some View {
        TabView {
            //Home Tab
            NavigationView {
                ScrollView(showsIndicators: false) {
                    ForEach(self.fbData.posts.indices, id: \.self) { postIndex in
                        PostView(post: self.$fbData.posts[postIndex])
                            .listRowInsets(EdgeInsets())
                            .padding(.vertical, 5)
                    }
                }
                .navigationBarTitle("MyPhotoApp", displayMode: .inline)
                .navigationBarItems(leading:
                    Button(action: {
                        print("Camera btn pressed")
                    }, label: {
                        Image(systemName: "camera")
                            .font(.title)
                    })
                , trailing:
                    Button(action: {
                        print("Messages btn pressed")
                    }, label: {
                        Image(systemName: "paperplane")
                            .font(.title)
                    })
                )
            } . tabItem({
                Image(systemName: "house")
                    .font(.title)
            })

            Text("Search").tabItem {
                Image(systemName: "magnifyingglass")
                    .font(.title)
            }

            Text("Upload").tabItem {
                Image(systemName: "plus.app")
                    .font(.title)
            }

            Text("Activity").tabItem {
                Image(systemName: "heart")
                    .font(.title)
            }

            Text("Profile").tabItem {
                Image(systemName: "person")
                    .font(.title)
            }
        }
        .accentColor(.black)
        .edgesIgnoringSafeArea(.top)
    }
}

FirebaseData

class FirebaseData : ObservableObject {
    @Published var posts = [Post]()

    let postsCollection = Firestore.firestore().collection("Posts")

    init() {
        self.fetchPosts()
    }

    //MARK: Fetch Data
    private func fetchPosts() {
        self.postsCollection.addSnapshotListener { (documentSnapshot, err) in
            if err != nil {
                print("Error fetching posts: \(err!.localizedDescription)")
                return
            } else {
                documentSnapshot!.documentChanges.forEach { diff in
                    if diff.type == .added {
                        let post = self.createPostFromDocument(document: diff.document)
                        self.posts.append(post)
                    } else if diff.type == .modified {
                        self.posts = self.posts.map { (post) -> Post in
                            if post.id == diff.document.documentID {
                                return self.createPostFromDocument(document: diff.document)
                            } else {
                                return post
                            }
                        }
                    } else if diff.type == .removed {
                        for index in self.posts.indices {
                            if self.posts[index].id == diff.document.documentID {
                                self.posts.remove(at: index)
                            }
                        }
                    }
                }
            }
        }
    }

【问题讨论】:

  • 你能发布更多关于 ObservableObject 如何链接到 ContentView 的代码吗?
  • 检查 stackoverflow.com/questions/60727556/… 并尝试了解 SwiftUI 如何知道要“刷新”、“重新加载”...等内容。您的数据和视图之间的关系是通过 '@State' 或 '@ ObservedObject 的属性包装器。 View 观察 State 或 ObservedObject 的内部,如果看到一些变化,它会重新评估其主体。仅此而已,背后没有奇迹。带有大量 .padding、.font .... 等的代码根本没有帮助。
  • @denis_lor 谢谢。我已经用更多信息更新了我的问题。
  • @user3441734 谢谢。我知道属性包装器是如何工作的,body 甚至可以正确回忆,但由于某种原因,只是 UI 本身没有改变。我已经添加了更多信息,如果你能看一下,我会很高兴
  • 请发布您的 ObservableObject,这可能是问题的关键部分。

标签: ios swift iphone swiftui combine


【解决方案1】:

您的代码示例无助于查找错误。最后我知道了如何演示它。首先,以“正确的方式”进行(复制-粘贴-自己尝试)

import SwiftUI

struct Data: Identifiable {
    let id = UUID()
    let text: String
}
class Model: ObservableObject {
    @Published var data: [Data] = [Data(text: "alfa"), Data(text: "beta")]
 }

struct ContentView: View {
    @ObservedObject var model = Model()
    var body: some View {
        TabView {
            View1(model: model).tabItem {
                Text("View 1")
            }
            View2(model: model).tabItem {
                Text("View 2")
            }
        }
    }
}

struct View1: View {
    @ObservedObject var model: Model
    var body: some View {
        VStack {
            Text("View 1").font(.largeTitle)
            DataView(data: model.data)
            Button(action: {
                self.model.data.append(Data(text: String("ABCDEFGH".shuffled())))
            }) {
                Text("Add random data")
            }
        }
    }
}
struct View2: View {
    @ObservedObject var model: Model
    var body: some View {
        VStack {
            Text("View 2").font(.largeTitle)
            DataView(data: model.data.filter({ (item) -> Bool in
                item.text.count < 4
                }))
                // to distinguish from other DataView !! it seems to be a bug in SwiftUI
                // try to remove it to see the difference
                .id("view2")
            Button(action: {
                self.model.data.append(Data(text: String("ABC".shuffled())))
            }) {
                Text("Add random data")
            }
        }
    }
}

struct DataView: View {
    var data: [Data]
    var body: some View {
        List {
            ForEach(data) { (item) in
                Text(item.text)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

我按原样工作,您可以修改每个选项卡中的数据,看到刷新的数据等。

移除“固定 - 用户定义” .id 修饰符,它会显着改变行为

这看起来像是 SwiftUI 中的一个严重错误 ...

【讨论】:

  • 我想你不明白我所说的“当我尝试切换到 TabView 上的另一个选项卡,然后切换回主视图时,UI 确实会更新”的意思。我不想在 Tab1 到 Tab2 之间传递信息。 posts 数组应该在 tab1 中。但由于某种原因,tab1 没有得到更新,就在我切换到 tab2(它只有一个 text 标题,仅此而已)并切换回 tab1 时,信息更新。您发布的代码类似于我的代码,但添加了另一个选项卡。所以不幸的是它不起作用。还有其他想法吗?
  • 在您发布一些最小的“工作”示例之前,我很抱歉……我在上面发布的是真正的错误,很难识别。我把它留给别人了……
  • 请在此处查看我更新的问题以及更多详细信息和代码:stackoverflow.com/questions/60740197/…
【解决方案2】:

我认为是 SwiftUI 错误。我这样解决这个问题。 而不是渲染你的 PostView(post: self.$fbData.posts[postIndex]) 在 ForEach 中实现 post 视图。

ForEach(self.fbData.posts.indices, id: \.self) { postIndex in
   Text(self.$fbData.posts[postIndex].comment)
   Text(self.$fbData.posts[postIndex].date)
   ....
}

【讨论】:

    猜你喜欢
    • 2019-10-31
    • 1970-01-01
    • 1970-01-01
    • 2018-04-29
    • 1970-01-01
    • 1970-01-01
    • 2011-09-27
    • 2010-10-09
    • 1970-01-01
    相关资源
    最近更新 更多