繁体   English   中英

使用 ObservableObject 时视图不会更新

[英]View doesn't get updated when using ObservableObject

我正在尝试使用 SwiftUI 构建 Instagram 克隆应用程序。

我正在通过Firebase获取数据,并在每次服务器中的数据发生更改时尝试实现 UI 更新。

出于某种原因,当我第一次打开应用程序并获取数据时,我的视图body被调用,但 UI 不会改变。 我什至设置了一个断点,看到body被调用并包含正确的信息,只是 UI 没有更新。

我在我的应用程序的几个标签,当我切换到另一个选项卡(不包含任何东西,但Text还),突然UI确实得到更新。

请看下面的gif:

gif

这是我的代码:

主页视图

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("Instagram", 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)
    }
}

火力地基数据

let firebaseData = 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)
                            }
                        }
                    }
                }
            }
        }
    }

    private func createPostFromDocument(document: QueryDocumentSnapshot) -> Post {
        let data = document.data()

        let id = document.documentID
        let imageUrl = data["imageUrl"] as! String
        let authorUsername = data["authorUsername"] as! String
        let authorProfilePictureUrl = data["authorProfilePictureUrl"] as! String
        let postLocation = data["postLocation"] as! String
        let postDescription = data["postDescription"] as! String
        let numberOfLikes = data["numberOfLikes"] as! Int
        let numberOfComments = data["numberOfComments"] as! Int
        let datePosted = (data["datePosted"] as! Timestamp).dateValue()
        let isLiked = data["isLiked"] as! Bool

        return Post(id: id, imageUrl: imageUrl, authorUsername: authorUsername, authorProfilePictureUrl: authorProfilePictureUrl, postLocation: postLocation, postDescription: postDescription, numberOfLikes: numberOfLikes, numberOfComments: numberOfComments, datePosted: datePosted, isLiked: isLiked)
    }
}

如果您需要我发布更多代码,请告诉我。

更新:

帖子视图

struct PostView: View {
    @Binding var post: Post

    var body: some View {
        VStack(alignment: .leading) {
            //Info bar
            HStack {
                WebImage(url: URL(string: post.authorProfilePictureUrl))
                    .resizable()
                    .frame(width: 40, height: 40)
                    .clipShape(Circle())

                VStack(alignment: .leading, spacing: 2) {
                    Text(post.authorUsername).font(.headline)
                    Text(post.postLocation)
                }

                Spacer()

                Button(action: {
                    print("More options pressed")
                }, label: {
                    Image(systemName: "ellipsis")
                        .font(.title)
                        .foregroundColor(.black)
                }).buttonStyle(BorderlessButtonStyle())
            }
            .padding(.horizontal)

            //Main Image
            WebImage(url: URL(string: post.imageUrl))
              .resizable()
              .aspectRatio(contentMode: .fit)

            //Tools bar
            HStack(spacing: 15) {
                Button(action: {
                    self.post.isLiked.toggle()
                    print("Like btn pressed")
                }, label: {
                    Image(systemName: post.isLiked ? "heart.fill" : "heart")
                        .font(.title)
                        .foregroundColor(.black)
                }).buttonStyle(BorderlessButtonStyle())

                Button(action: {
                    print("Comments btn pressed")
                }, label: {
                    Image(systemName: "message")
                        .font(.title)
                        .foregroundColor(.black)
                }).buttonStyle(BorderlessButtonStyle())

                Button(action: {
                    print("Share btn pressed")
                }, label: {
                    Image(systemName: "paperplane")
                        .font(.title)
                        .foregroundColor(.black)
                }).buttonStyle(BorderlessButtonStyle())

                Spacer()

                Button(action: {
                    print("Bookmark btn pressed")
                }, label: {
                    Image(systemName: "bookmark")
                        .font(.title)
                        .foregroundColor(.black)
                }).buttonStyle(BorderlessButtonStyle())
            }.padding(8)

            Text("Liked by \(post.numberOfLikes) users")
                .font(.headline)
                .padding(.horizontal, 8)

            Text(post.postDescription)
                .font(.body)
                .padding(.horizontal, 8)
                .padding(.vertical, 5)

            Button(action: {
                print("Show comments btn pressed")
            }, label: {
                Text("See all \(post.numberOfComments) comments")
                    .foregroundColor(.gray)
                    .padding(.horizontal, 8)
            }).buttonStyle(BorderlessButtonStyle())

            Text(post.datePostedString)
                .font(.caption)
                .foregroundColor(.gray)
                .padding(.horizontal, 8)
                .padding(.vertical, 5)
        }
    }
}

发布

struct Post : Identifiable, Hashable {
    var id: String
    var imageUrl: String
    var authorUsername: String
    var authorProfilePictureUrl: String
    var postLocation: String
    var postDescription: String
    var numberOfLikes: Int
    var numberOfComments: Int
    var datePostedString: String

    var isLiked: Bool

    init(id: String, imageUrl: String, authorUsername: String, authorProfilePictureUrl: String, postLocation: String, postDescription : String, numberOfLikes: Int, numberOfComments: Int, datePosted: Date, isLiked: Bool) {
        self.id = id
        self.imageUrl = imageUrl
        self.authorUsername = authorUsername
        self.authorProfilePictureUrl = authorProfilePictureUrl
        self.postLocation = postLocation
        self.postDescription = postDescription
        self.numberOfLikes = numberOfLikes
        self.numberOfComments = numberOfComments

        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MMMM dd, yyyy"
        self.datePostedString = dateFormatter.string(from: datePosted)

        self.isLiked = isLiked
    }
}

谢谢!

问题是,当应用程序启动时,您的数组为空,并且 ScrollView 停止更新,您可以将其替换为 VStack 并且它会起作用(仅用于测试)。

解决方案是使用条件包装ForEach (或 ScrollView),如下所示:

if (fbData.posts.count > 0) {
    ForEach(self.fbData.posts.indices, id: \.self) { postIndex in
        PostView(post: self.$fbData.posts[postIndex])
            .listRowInsets(EdgeInsets())
            .padding(.vertical, 5)
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM