【问题标题】:Firestore not updating SwiftUI grid without reloading the appFirestore 在不重新加载应用程序的情况下不更新 SwiftUI 网格
【发布时间】:2020-08-24 15:37:33
【问题描述】:

我按照在线教程进行操作,似乎有一些工作正常,但是我正在尝试根据有效的订单自动更新我的视图,但前提是我关闭并重新打开应用程序。

Observer.swift

class postsobserver: ObservableObject {
    @Published var posts = [datatype1]()

    init() {
        let settings = FirestoreSettings()
        settings.isPersistenceEnabled = true

        let db = Firestore.firestore()
        db.settings = settings

        db.collection("posts").order(by: "likes", descending: true).addSnapshotListener { snap, err in

            if err != nil {
                print((err?.localizedDescription)!)

                return
            }

            for i in snap!.documentChanges {
                if i.type == .added {
                    let id = i.document.documentID
                    let name = i.document.get("name") as! String
                    let image = i.document.get("image") as! String
                    let likes = i.document.get("likes") as! String

                    self.posts.append(datatype1(id: id, name: name, image: image, likes: likes))
                }

                if i.type == .removed {
                    let id = i.document.documentID

                    for j in 0 ..< self.posts.count {
                        if self.posts[j].id == id {
                            self.posts.remove(at: j)
                            return
                        }
                    }
                }

                if i.type == .modified {
                    let id = i.document.documentID
                    let likes = i.document.get("likes") as! String

                    for j in 0 ..< self.posts.count {
                        if self.posts[j].id == id {
                            self.posts[j].likes = likes
                            return
                        }
                    }
                }
            }
        }
    }
}

Home.swift

@ObservedObject var postsobserved = postsobserver()

let columns = [
    GridItem(.adaptive(minimum: 100)),
]

var body: some View {
    ScrollView(.vertical, showsIndicators: false) {
        VStack {
            if postsobserved.posts.isEmpty {
                Text("no new posts").fontWeight(.heavy)
            } else {
                LazyVGrid(columns: columns, spacing: 20) {
                    ForEach(postsobserved.posts) { i in

                        postCard(user: i.name, image: i.image, id: i.id, likes: i.likes)
                    }
                }
            }
        }
    }
}

postCard.swift

import SwiftUI
import SDWebImageSwiftUI
import Firebase
import FirebaseFirestore

struct postCard: View {
    var user = ""
    var image = ""
    var id = ""
    var likes = ""

    var body: some View {
        VStack(alignment: .leading) {
            HStack {
                Text(user)
                Spacer()
            }

            AnimatedImage(url: URL(string: image))
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(height: 100)

            HStack {
                Button(action: {
                    let db = Firestore.firestore()

                    let like = Int.init(self.likes)!
                    db.collection("posts").document(self.id).updateData(["likes": "\(like + 1)"]) { err in

                        if err != nil {
                            print(err)
                            return
                        }

                        print("updated...")
                    }

                }) {
                    Image(systemName: "arrow.up.square")
                        .frame(width: 26, height: 26)
                }

                Button(action: {
                    let db = Firestore.firestore()

                    let like = Int.init(self.likes)!
                    db.collection("posts").document(self.id).updateData(["likes": "\(like - 1)"]) { err in

                        if err != nil {
                            print(err)
                            return
                        }

                        print("updated...")
                    }

                }) {
                    Image(systemName: "arrow.down.square")
                        .frame(width: 26, height: 26)
                }

                Spacer()

            }.padding(.top, 8)

            Text("\(likes) Likes")

        }.padding(8)
    }
}

我很确定我在某处犯了错误,但在过去 4 小时内尝试了一些事情,我认为是时候寻求帮助了

编辑:

当我单击箭头时,它们似乎可以正确更新而无需重新加载应用程序,但 .order(by: "likes", descending: true) 似乎不会改变顺序,除非我重新加载应用程序。

【问题讨论】:

    标签: swift google-cloud-firestore swiftui


    【解决方案1】:

    您需要在主线程上更新您的@Published 属性。

    看起来db.collection("posts").order(by: "likes", descending: true).addSnapshotListener 是异步的——即。在后台运行。

    无论您在哪里更新 posts 变量:

    self.posts.append(datatype1(id: id, name: name, image: image, likes: likes))
    

    self.posts.remove(at: j)
    

    等等……

    把它包裹在DispatchQueue.main:

    DispatchQueue.main.async {
        self.posts.append(datatype1(id: id, name: name, image: image, likes: likes))
    }
    

    您还可以将所有代码包装在DispatchQueue.main 中的异步响应中:

    db.collection("posts").order(by: "likes", descending: true).addSnapshotListener { (snap, err) in
        DispatchQueue.main.async {
            ...
        }
    }
    

    编辑

    您似乎只在init 中重新加载您的帖子。这就是为什么它只在开始时是正确的(当你打开应用程序时)。如果您想在某些操作中重新加载它们,请尝试以下操作:

    class postsobserver: ObservableObject {
        @Published var posts = [datatype1]()
        
        private let settings = FirestoreSettings()
        private let db = Firestore.firestore()
    
        init() {
            settings.isPersistenceEnabled = true
            db.settings = settings
    
            loadPosts()
        }
        
        // function to reload your posts (in the correct order)
        func loadPosts() {
            db.collection("posts").order(by: "likes", descending: true).addSnapshotListener { snap, err in
                DispatchQueue.main.async {
                    // ...
                }
            }
        }
    }
    

    然后在您想要加载更新的帖子时从您的视图中调用它:

    postsobserved.loadPosts()
    

    或者,您可以在本地对帖子进行排序,而不是每次都重新加载帖子:

    ForEach(postsobserved.posts.sorted(by: { /* condition */ })) {i in ...
    

    注意:我还建议您将 Firebase 逻辑移至 ObservableObject。

    此按钮操作:

    Button(action: {
        let db = Firestore.firestore()
    
        let like = Int(self.likes)!
        db.collection("posts").document(self.id).updateData(["likes": "\(like - 1)"]) { err in
    
            if err != nil {
                print(err)
                return
            }
    
            print("updated...")
        }
    
    }) {
        Image(systemName: "arrow.down.square")
            .frame(width: 26, height: 26)
    }
    

    可以提取到postsobserver 中的某个函数,并直接在Button 中调用:

    Button(action: {
        postsobserver.updateLikes(...)
    }) {
        Image(systemName: "arrow.down.square")
            .frame(width: 26, height: 26)
    }
    

    【讨论】:

    • 将代码包装在 DispatchQueue.main 中似乎运行没有错误,但似乎仍然没有更新网格,我添加了 postCard.swift 以防我在那里做错了什么
    • @zeem 您是否检查(打印、调试)您的异步 firebase 函数是否按预期返回所有内容?
    • 它似乎运行正常,只是滚动视图/LazyVGrid 似乎没有在不重新加载应用程序的情况下更新订单。
    • 感谢@pawello2222 进行了更改,但是不确定在哪里调用我在 else 之后添加为 .onAppear 语句的 postobserved.loadPosts() 但认为它只是循环并得到错误“每个布局项可能只发生一次..” ForEach(postsobserved.posts.sorted(按条件,似乎不喜欢添加“喜欢”时似乎只是崩溃了。我有一种感觉我在某处做一些非常愚蠢的事情
    • 有时你只需要一杯更浓的咖啡 :) 非常感谢你的帮助 @pawello2222 ForEach(postsobserved.posts.sorted(by: { $0.likes > $1.likes })){I in ... 解决了它现在应该工作的问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-13
    • 2017-12-12
    • 2021-11-15
    • 2010-12-28
    • 2019-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多