我正在制作一个社交应用程序,我正在该社交应用程序中获取一些数据并将其刷新到集合视图。我正在将所有帖子从firebase刷新到posts数组。我也正在获取发布特定图像的用户信息。这两个数据库都是2个不同的模型。以下是我的数据模型:
posts
|- <post_id>
|- caption
|- ImageURL
|- views
|- spot
|- spot_id
|- sender<user_id>
|- spotted(value)
|- timestamp
|- author(<user_id>)
users
|- <user_id>
|- name
以下是我在collectionVC中获取发布数据并将所有数据存储到posts数组的方式:
func initialiseAllPostsContent(){
FBDataservice.ds.REF_CURR_USER.child("connections/following").observe(.childAdded) { (snapshot) in
if let snapshot = snapshot.value as? String {
self.followerKeys.append(snapshot)
}
}
if uid != nil {
self.followerKeys.append(uid!)
}
FBDataservice.ds.REF_POSTS.queryOrdered(byChild: "timestamp").observe(.childAdded, with: { (snapshot) in
print("post key is ", snapshot.key)
if let postDict = snapshot.value as? Dictionary<String, Any> {
let key = snapshot.key
if let postAuthor = postDict["author"] as? String {
for user in self.followerKeys {
if postAuthor == user {
let post = Posts(postId: key, postData: postDict)
self.posts.append(post)
}
}
}
}
})
reloadCollectionViewData()
}
func reloadCollectionViewData() {
FBDataservice.ds.REF_POSTS.queryOrdered(byChild: "timestamp").observe(.value) { (snapshot) in
self.collectionView.reloadData()
}
}
//I am updating the views on the post after a method is successfull. As soon as this is called, and then if like is pressed, views flicker
func updateViews(postid: String, views: Int) {
let viewref = FBDataservice.ds.REF_POSTS.child(postid)
let newviews = views + 1
viewref.updateChildValues(["views":newviews])
}
// fetching the user data from the post data
func getAllPosts(pid: String, completion: @escaping ((String) -> ())) {
FBDataservice.ds.REF_POSTS.child(pid).observeSingleEvent(of: .value) { (snapshot) in
if let snapshot = snapshot.value as? Dictionary<String, Any> {
if let userid = snapshot["author"] as? String {
completion(userid)
}
}
}
}
func getpostAuthorData(authorId : String, completion: @escaping (User) -> ()) {
FBDataservice.ds.REF_USERS.child(authorId).observeSingleEvent(of: .value) { (snapshot) in
if let snapshot = snapshot.value as? Dictionary<String, Any> {
if let userCredential = snapshot["credentials"] as? Dictionary<String, Any> {
completion(User(userid: authorId, userData: userCredential))
}
}
}
}
这就是我在cellForItemAtIndexPath
中分配数据的方式
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
self.posts.sort(by: { $0.timestamp < $1.timestamp})
let post = posts[indexPath.row]
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as? SpotGroundCell {
cell.configureCellData(post: post)
getAllPosts(pid: post.postId) { (userid) in
self.getpostAuthorData(authorId: userid, completion: { (userdata) in
cell.configUserData(user: userdata)
})
}
return cell
} else {
return SpotGroundCell()
}
}
我的单元格中的代码:
//Consider this as likes. I allow users to like multiple times. Once the model is loaded, it fetches all the spots according to the timestamp and then siplayer the most recent ones. Even this is doesn't display according to the current image and flickers. I replicate previous cell values even though I am refreshing the view.
var currentUserSpots = [Spot]() {
didSet {
self.currentUserSpots.sort(by: { $0.timestamp < $1.timestamp})
if !self.currentUserSpots.isEmpty {
self.emotionImage.image = UIImage(named: (self.currentUserSpots.first?.spotted)!)
self.emotionImage.alpha = 1
} else {
self.emotionImage.image = UIImage(named: "none")
self.emotionImage.alpha = 0.5
}
}
}
func configUserData(user: User) {
self.user = user
self.name.text = self.user.name
}
func configureCellData(post: Posts) {
print("Config is now called")
self.posts = post
self.caption.text = posts.caption
FBDataservice.ds.REF_POSTS.child(post.postId).child("spot").queryOrdered(byChild: "senderID").queryEqual(toValue: uid!).observeSingleEvent(of: .childAdded) { (snapshot) in
if let spotData = snapshot.value as? Dictionary<String, Any> {
let spot = Spot(id: snapshot.key, spotData: spotData)
if spot.spotted != nil {
self.currentUserSpots.append(spot)
}
}
}
}
现在,无论何时我进行更改或更新数据库的事件(例如更新视图)。我在用户对象实体(例如名称等)中看到了闪烁。该事件还会杀死其他进程和通知观察者。
我为解决方案放弃了互联网,但到目前为止只能find one,但这并不能解决我的问题。
任何帮助将不胜感激。我真的不确定我要去哪里错了。
答案 0 :(得分:1)
您现在REF_POSTS
下的任何更改:
鉴于大多数更改只会影响列表中的一项,因此您使N-1的视图超出了所需的范围。这会导致闪烁。
要解决此问题,您应该侦听数据库中更详细的信息。除了观察.value
之外,还添加.childAdded
的侦听器。每当添加新孩子时,都会触发此侦听器的完成块,此时,您只需将新孩子添加到视图中即可。
FBDataservice.ds.REF_POSTS.queryOrdered(byChild: "timestamp").observe(.childAdded, with: { (snap) in
if let postDict = snap.value as? Dictionary<String, Any> {
let key = snap.key
if let postAuthor = postDict["author"] as? String {
for user in self.followerKeys {
if postAuthor == user {
let post = Posts(postId: key, postData: postDict)
self.posts.append(post)
}
}
}
}
})
作为奖励,.childAdded
也会立即为所有现有的子节点触发,因此您不再需要.value
的观察者。我喜欢自己保留它。由于Firebase保证会在所有相应的.value
事件之后触发child*
,因此.value
事件是一个很好的时刻,可以告诉视图所有更改都已进入。
FBDataservice.ds.REF_POSTS.queryOrdered(byChild: "timestamp").observe(.value, with: { (snapshot) in
self.collectionView.reloadData()
})
您还需要一些其他东西来完成完整的实现:
.childChanged
,.childMoved
和childRemoved
来处理对数据库的这些类型的更改。observe(_, andPreviousSiblingKey: )
才能将该项放置在列表中的正确位置。