UITableView无法正确刷新数据:已回答的最后一条问题未移除
我来帮你搞定这个最后一条问题无法移除的bug,这个问题主要出在Firebase数据监听的逻辑和表格刷新的时机上,咱们一步步来修复:
1. 修正Firebase数据监听的处理逻辑
你原来的代码里,只有当snapshot.childrenCount>0时才会清空quesList,但当最后一条问题被回答后,Firebase返回的snapshot会变成空(childrenCount=0),这时候不会执行清空操作,导致旧数据还留在列表里。咱们把清空列表的代码移到判断外面,不管有没有数据都先清空,再重新加载最新数据:
func fetchQues(){ Ref.queryOrdered(byChild: currentuser).queryEqual(toValue: nil).observe(DataEventType.value, with:{(snapshot)in // 先清空旧数据,无论有没有新数据都要执行 self.quesList.removeAll() if snapshot.childrenCount > 0{ for data in snapshot.children.allObjects as![DataSnapshot]{ let dataObject = data.value as? [String: AnyObject] // 用guard let替代强制解包,避免崩溃 guard let userid = dataObject?["sender_id"] as? String, let username = dataObject?["sender_name"] as? String, let questext = dataObject?["text"] as? String, let questionid = dataObject?["id"] as? String else { continue } let question = Question(id: questionid, sender_id: userid, sender_name: username, text: questext) self.quesList.insert(question, at: 0) } } // 确保表格刷新在主线程执行(Firebase回调默认在后台线程) DispatchQueue.main.async { self.AnswerTable.reloadData() } }) }
2. 确保返回列表页时主动刷新数据
虽然Firebase的observe是实时监听,但有时候返回页面时,监听可能没有及时触发最新的value事件(比如缓存或者状态问题)。咱们在列表页的viewWillAppear方法里,先移除旧的监听,再重新获取数据,保证每次进入页面都是最新状态:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 移除之前的监听,避免重复监听导致多次刷新 Ref.removeAllObservers() // 重新拉取最新的未回答问题列表 fetchQues() }
3. 额外优化:避免强制解包崩溃
你原来的代码里用了很多as!强制解包,一旦Firebase返回的数据格式有问题,就会导致崩溃。上面的代码已经改成用guard let来安全解包,这样就算数据异常,也只会跳过这条数据,不会崩溃。
为什么原来的代码会失效?
当列表只剩最后一条问题时,你回答后Firebase里对应的数据会被更新,此时queryOrdered(byChild: currentuser).queryEqual(toValue: nil)查询不到数据,snapshot.childrenCount变成0,原来的代码不会执行quesList.removeAll(),所以旧的那条数据还留在数组里,表格自然不会更新。把清空操作移到判断外面后,不管有没有数据都会清空旧数组,再重新加载最新数据,就解决了这个问题。
内容的提问来源于stack exchange,提问作者frankcrest

