Swift中返回聊天列表后TableView调用reloadData仍不更新问题
解决Socket.IO聊天页面二次进入后TableView不更新的问题
嘿,我帮你分析下当前遇到的问题——首次进入聊天页面正常,返回再进入后收发消息调用reloadData却没反应,大概率是线程问题+重复注册回调导致的,下面给你一步步的解决方案:
1. 必须把UI操作放到主线程
Socket.IO的回调默认是在后台线程执行的,而iOS所有UI更新必须在主线程完成。你现在直接在回调里操作TableView和输入框,第一次可能碰巧在主线程(或者系统做了兼容),但二次进入后线程问题就会暴露出来,导致UI不更新。
修改你的回调代码,把所有和UI相关的逻辑包裹进DispatchQueue.main.async:
SocketIOManager.sharedInstance.getChatMessage { (messageInfo) -> Void in // 数据解析可以在后台,但所有UI操作必须切到主线程 DispatchQueue.main.async { self.txtField_Chat.text = "" self.isSendBtnEnabled(val: false) // ---------- 原有的数据解析代码 ---------- let result_arr = messageInfo["data"] as! NSArray let result_dic = result_arr[0] as? NSDictionary let result_string_date : String = result_dic!.value(forKey: "date") as! String let result_array : NSArray = result_dic!.value(forKey: "value") as! NSArray let result_dic_value : NSDictionary = result_array[0] as! NSDictionary if self.arr_message_All.count > 0{ let recentdate_dic : NSDictionary = self.arr_message_All[self.arr_message_All.count - 1] as NSDictionary let recentdate : String = recentdate_dic.value(forKey: "date") as! String let recentdate_array : NSArray = recentdate_dic.value(forKey: "value") as! NSArray let recentdate_arrayM : NSMutableArray = recentdate_array.mutableCopy() as! NSMutableArray let dic_message = Message(dictionary: result_dic_value.value(forKey: "message") as! NSDictionary) var get_msg_id : String = "" if let msg_id = defaults.value(forKey: "m_id") as? String{ get_msg_id = msg_id } if !(dic_message?.msg_m_id == get_msg_id){ if (messageInfo["status"] as! NSString) == "Success"{ recentdate_arrayM.add(result_dic_value) let dic = ["date":recentdate , "value" : recentdate_arrayM] as NSDictionary self.arr_message_All[(self.arr_message_All.count) - 1] = dic // 所有TableView操作移到主线程内 self.tblView_chat.reloadData() let lastSectionIndex = self.tblView_chat.numberOfSections - 1 let lastRowIndex = self.tblView_chat.numberOfRows(inSection: lastSectionIndex) let pathToLastRow = IndexPath(row: lastRowIndex, section: lastSectionIndex) self.tblView_chat.scrollToRow(at: pathToLastRow, at: .none, animated: true) } else{ self.arr_message_All.append(result_dic!) self.tblView_chat.reloadData() self.scrollToBottomOfChat() } } } defaults.set(dic_message?.msg_m_id, forKey: "m_id") } }
2. 避免重复注册Socket回调
你在viewDidAppear里注册回调,每次进入页面都会绑定一次,导致第二次进入时,旧的ViewController实例(可能还没被销毁)依然在接收消息,而当前页面的数据源没被正确更新。
解决方法是在页面离开时解绑回调:
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 需要你的SocketIOManager提供移除监听的方法,比如移除对应的handler SocketIOManager.sharedInstance.removeChatMessageListener() }
确保SocketIOManager里有对应的移除逻辑,比如维护一个回调数组,移除当前页面绑定的闭包。
3. 简化TableView更新逻辑
你现在混合使用reloadData()和beginUpdates()/endUpdates(),容易出现索引计算错误。建议简化逻辑:
- 如果只是追加消息,直接更新数据源后调用
reloadData(),再滚动到底部即可 - 避免手动计算插入的IndexPath,减少出错概率
额外优化建议
把代码里的NSArray/NSDictionary换成Swift原生的[Any]/[String: Any]或者自定义模型,类型更安全,也更容易排查数据更新的问题。比如把Message改成Swift的struct,用Codable解析数据,比手动转字典靠谱得多。
内容的提问来源于stack exchange,提问作者Gaurav
相关产品推荐
相关产品推荐

