Firestore 在不重新加载应用程序的情况下不更新 SwiftUI 网格
Posted
技术标签:
【中文标题】Firestore 在不重新加载应用程序的情况下不更新 SwiftUI 网格【英文标题】:Firestore not updating SwiftUI grid without reloading the app 【发布时间】: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)
似乎不会改变顺序,除非我重新加载应用程序。
【问题讨论】:
【参考方案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 ... 解决了它现在应该工作的问题以上是关于Firestore 在不重新加载应用程序的情况下不更新 SwiftUI 网格的主要内容,如果未能解决你的问题,请参考以下文章
System.load() 方法在不设置 LD_LIBRARY_PATH 环境变量的情况下不加载共享库
我们可以在不重新设置整个适配器的情况下更新 Firestore 回收器适配器的查询吗?
jquery 数据表头在某些情况下不扩展或扩展缓慢,例如重新加载
如何在不重新加载页面的情况下重新启动 Angular 应用程序?