TabBar控制器中CollectionView reloadData无效及重复数据问题求助
解决TabBar嵌套ViewController中reloadData无效及数据重复问题
先帮你揪出代码里的几个关键问题,这就是导致你遇到这些现象的根源:
- 下拉刷新根本没干活:你的
refreshData方法只结束了刷新控件的动画,完全没触发重新加载数据的逻辑,所以下拉刷新当然没效果。 - 数组越堆越多:每次调用
lodPosts()时,following和posts数组都是往里面追加元素,从来不清空,不管是下拉刷新还是从其他页面切回来调用,都会重复添加相同数据。 - UI刷新可能在后台线程:Firebase的数据库回调是在后台线程跑的,直接在回调里调用
collectionview.reloadData(),系统可能不会处理这个UI操作,导致刷新无效。
接下来咱们一步步解决这些问题:
1. 让下拉刷新真正生效
修改refreshData方法,先清空旧数据,再重新加载,把结束刷新的操作放到数据加载完成后(避免刷新动画提前结束):
@objc func refreshData() { // 先清空数组,避免旧数据残留 posts.removeAll() following.removeAll() // 触发重新加载数据 lodPosts() }
2. 修复lodPosts(),彻底解决重复数据+确保UI刷新生效
在lodPosts()开头就清空两个数组,并且把所有UI相关操作(刷新集合视图、结束下拉刷新)放到主线程执行:
func lodPosts() { // 每次加载前强制清空数组,从根源杜绝重复数据 posts.removeAll() following.removeAll() let ref = Database.database().reference() ref.child("users").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in // 先做安全校验,避免强制解包崩溃 guard let users = snapshot.value as? [String : AnyObject] else { // 没有数据的话,也要刷新UI并结束刷新 DispatchQueue.main.async { self.collectionview.reloadData() self.refreshControl.endRefreshing() } return } for (_, value) in users { guard let uid = value["uid"] as? String, uid == Auth.auth().currentUser?.uid else { continue } // 添加关注的用户ID到列表 if let followingUsers = value["following"] as? [String : String] { for (_, user) in followingUsers { self.following.append(user) } } // 别忘了添加当前用户自己的ID self.following.append(Auth.auth().currentUser!.uid) // 查询帖子数据 ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in guard let postsSnap = snap.value as? [String: AnyObject] else { DispatchQueue.main.async { self.collectionview.reloadData() self.refreshControl.endRefreshing() } return } for (_, post) in postsSnap { guard let userID = post["uid"] as? String else { continue } // 只保留关注用户或自己的帖子 if self.following.contains(userID) { // 安全解析帖子数据,避免强制解包崩溃 guard let author = post["Author"] as? String, let likes = post["likes"] as? Int, let pathToImage = post["photoUrl"] as? String, let postID = post["postID"] as? String, let profileImage = post["profileImageUrl"] as? String, let caption = post["caption"] as? String else { continue } let newPost = Post() newPost.author = author newPost.likes = likes newPost.pathToImage = pathToImage newPost.postID = postID newPost.userID = userID newPost.userimage = profileImage newPost.caption = caption self.posts.append(newPost) } } // 必须在主线程更新UI! DispatchQueue.main.async { self.collectionview.reloadData() self.refreshControl.endRefreshing() } }) } }) }
3. 解决viewWillAppear重复加载的问题
如果你希望每次切回这个页面都刷新数据,直接在viewWillAppear里调用lodPosts()就行——因为我们已经在lodPosts()开头清空了数组,所以不会再出现重复数据:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 每次进入页面都刷新数据 lodPosts() }
要是不想每次都请求数据库(比如用户刚刷新过就切回来),可以加个判断,只在数组为空时加载:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 只有当没有数据时才加载 if posts.isEmpty { lodPosts() } }
额外优化:提升帖子查询效率
你现在的逻辑是遍历所有帖子再判断是否属于关注用户,当帖子多了之后会很慢。可以改成直接查询目标用户的帖子,用Firebase的query(in:)方法(记得给posts节点的uid字段加索引):
// 替换原来的帖子查询代码 ref.child("posts") .queryOrderedByChild("uid") .query(in: self.following) // 直接获取关注用户的帖子,不用遍历所有数据 .observeSingleEvent(of: .value, with: { (snap) in // 后续的解析和UI刷新逻辑不变 // ... })
内容的提问来源于stack exchange,提问作者luke mier
相关产品推荐
相关产品推荐

