Reputation: 1181
VStack(spacing: 0){
List{
ForEach(postsData.fetchedPosts, id: \.postID) { post in
SocialPostView(post: post, showAccount: self.$showAccount, fetchedUser: self.$fetchedUser)
.padding(.vertical)
.listRowInsets(EdgeInsets())
.onAppear {
self.elementOnAppear(post)
}
}
}
.pullToRefresh(isShowing: $isShowing) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.isShowing = false
self.postsData.newFetch = true
self.postsData.fetchPosts(userInfo: self.userInfo)
}
}
}
private func elementOnAppear(_ post: Post) {
/* onAppear on the view is called when a view appears on screen.
elementOnAppear asks the view model if the element is the last one.
If so, we ask the view model to fetch new data. */
if self.postsData.isLastPostInList(post: post) {
self.postsData.fetchPosts(userInfo: self.userInfo)
}
}
When each list element appears, it checks if it's the last element in the array. If it is, it fetches more from Firestore and updates fetchedPosts
. However, when the array updates, the List is not updated, so no new elements show up.
This is the ObservableObject, which publishes the array.
class SocialObservable: ObservableObject{
let db = Firestore.firestore()
let objectWillChange = ObservableObjectPublisher()
@Published var fetchedPosts = [Post]()
@Published var lastSnap : DocumentSnapshot?
@Published var reachedEnd = false
var currentListener: ListenerRegistration?
var newFetch = false {
willSet{
objectWillChange.send()
}
}
init(userInfo: UserData){
print(userInfo.uid)
fetchPosts(userInfo: userInfo)
}
func fetchPosts(userInfo: UserData){
var first: Query?
if lastSnap == nil || newFetch {
//not last snapshot, or just updated feed
if newFetch{
newFetch.toggle()
fetchedPosts = [] // clean up if new fetch
}
first = db.collection("posts")
.whereField("availability", arrayContains: userInfo.uid)
.order(by: "date", descending: true)
.limit(to: 1)
}
else {
first = db.collection("posts")
.whereField("availability", arrayContains: userInfo.uid)
.order(by: "date", descending: true)
.start(afterDocument: lastSnap!)
.limit(to: 1)
}
first?.getDocuments(completion: { (snapshot, error) in
guard let snapshot = snapshot else {
print("Error: \(error.debugDescription)")
return
}
let doc = snapshot.documents.map({postFromDB(obj: $0.data(), id: $0.documentID)})
doc.map({print($0.postID)})
// append to fetched posts
self.fetchedPosts = self.fetchedPosts + doc
print(self.fetchedPosts.count)
//prepare for the next fetch
guard let lastSnapshot = snapshot.documents.last else {
// the collection is empty. no data fetched
self.reachedEnd = true
return
}
// save last snapshot
self.lastSnap = lastSnapshot
})
}
func isLastPostInList(post: Post) -> Bool {
return post.postID == fetchedPosts.last?.postID
}
}
Is there any workaround for this?
Upvotes: 3
Views: 1314
Reputation: 257563
A couple of things
class SocialObservable: ObservableObject{
let db = Firestore.firestore()
// let objectWillChange = ObservableObjectPublisher() // << remove this
// ...
var newFetch = false {
willSet{
self.objectWillChange.send() // ObservableObject has default
}
}
// ...
and on update modify published on main queue
doc.map({print($0.postID)})
// append to fetched posts
DispatchQueue.main.async {
self.fetchedPosts = self.fetchedPosts + doc
}
print(self.fetchedPosts.count)
Upvotes: 1