Swift中使用.reverse()反转Firebase数据时出现元素顺序错误
解决Firebase数据反转顺序的问题
我明白你遇到的麻烦了——每次用reverse()之后,第二个元素总会跑到末尾,这确实闹心。咱们先搞清楚问题出在哪,再给你最适合的解决方案。
问题根源:childAdded + 每次reverse()的矛盾
Firebase的.childAdded观察者是逐个返回数据的:初始加载时会按数据库的默认顺序(比如push生成的key是时间递增,最早的post先返回)依次触发,之后有新post添加时也会触发一次。
你现在的代码是每次拿到新post就append到数组末尾,然后立刻reverse整个数组。咱们模拟一下过程就懂了:
- 第一个post回来:数组是
[post1],reverse后还是[post1]——没问题 - 第二个post回来:数组变成
[post1, post2],reverse后变成[post2, post1]——看起来还行 - 第三个post回来:数组变成
[post2, post1, post3],reverse后变成[post3, post1, post2]——这就出问题了!post1被挤到了倒数第二位,完全不是你想要的反转顺序
最优方案:直接插入数组开头(无需创建新数组)
既然想要反转顺序,那不如把新拿到的post直接插在数组的最前面,这样既不用反转整个数组,也不会打乱已有顺序,完全符合你“无需创建新数组”的要求。
把你代码里的这两行:
postsArray.append(post) postsArray.reverse()
改成:
postsArray.insert(post, at: 0)
就搞定了!
这个方案的逻辑是:
- 初始加载时,最早的post先被返回,插入到数组开头→接下来的post(晚一点的)再插开头,最终数组就是
[最新post, ..., 最早post],正好是反转后的顺序 - 之后新增的post会直接插在数组最前面,完美保持反转顺序
备选方案:初始加载完再反转(适合需要批量处理的场景)
如果你一定要用reverse(),那得等所有初始数据加载完成后再一次性反转,而不是每次childAdded都反转。可以用.value事件先获取全部数据,再处理后续的新增post:
// 第一步:获取所有初始数据,原地反转后赋值 Database.database().reference().child("posts").observeSingleEvent(of: .value) { snapshot in var tempPosts = [Post]() for child in snapshot.children { guard let childSnapshot = child as? DataSnapshot, let dictionary = childSnapshot.value as? Dictionary<String, AnyObject> else { continue } let post = Post(postid: childSnapshot.key, dictionary: dictionary) tempPosts.append(post) } // 原地反转数组,不需要创建新数组 tempPosts.reverse() self.postsArray = tempPosts self.finishedFetching = true self.collectionView.reloadData() } // 第二步:监听后续新增的post,直接插入到数组开头 Database.database().reference().child("posts").observe(.childAdded) { snapshot in guard let dictionary = snapshot.value as? Dictionary<String, AnyObject> else { return } let post = Post(postid: snapshot.key, dictionary: dictionary) self.postsArray.insert(post, at: 0) self.collectionView.reloadData() }
这里用observeSingleEvent(of: .value)只获取一次初始数据,避免和.childAdded的重复触发,之后新增的post还是插开头保持顺序。
内容的提问来源于stack exchange,提问作者antonklimenko
相关产品推荐
相关产品推荐

