swift - Firebase Data 在添加新值时闪烁
问题描述
我正在制作一个社交应用程序,我正在获取一些数据并将其刷新到集合视图。我正在将所有帖子从 firebase 刷新到帖子数组。我还在获取发布特定图像的用户信息。两个数据库都是 2 个不同的模型。以下是我的数据模型:
posts
|- <post_id>
|- caption
|- ImageURL
|- views
|- spot
|- spot_id
|- sender<user_id>
|- spotted(value)
|- timestamp
|- author(<user_id>)
users
|- <user_id>
|- name
以下是我在 collectionVC 中获取帖子数据并将所有内容存储到帖子数组的方式:
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)
}
}
}
}
现在,每当我进行更改或更新数据库的事件(例如更新视图)时。我在用户对象实体(例如名称等)中看到闪烁。该事件还会杀死其他进程和通知观察者。
我放弃了互联网的解决方案,但到目前为止只能找到一个,这并不能解决我的问题。
任何帮助将不胜感激。我真的不确定我哪里出错了。
解决方案
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: )
能够将项目放在列表中的正确位置。
推荐阅读
- react-native - 是否可以将 React-Native webview 容器附加到背景,使其不会移动?
- android - 无法通过 `api` 方法从 Android 模块解析主题和样式
- bokeh - 通过 Chrome 访问 AWS EMR Dask 集群 Bokeh 仪表板的问题
- php - ' Socket.io 'WebSocket 在连接建立之前关闭。'
- python - 循环Python期间的Iter()
- java - Gradle bintrayUpload 找不到生成的 jar
- c++ - 使用加密密码连接到 MySQL
- java - Dagger2:从单例组件返回不是单例对象
- angular - 错误:无法读取未定义的属性“推送”
- c# - 是否可以将用户过去的对话历史插入/注入聊天窗口对话框?