UITableView滑动或触摸时无法刷新数据或给cell赋值如何解决?
问题根因
当UITableView处于滑动/触摸交互状态时,主线程RunLoop会切换到NSEventTrackingRunLoopMode(iOS系统为了保证滑动流畅性设计的专属模式),该模式下默认只会处理和触摸交互相关的任务:
- 如果你的Socket监听任务是注册在
NSDefaultRunLoopMode下,滑动时Socket的回调会被暂时挂起,你不会收到新数据,自然不会触发刷新 - 即使你收到了数据,如果刷新UI的任务只注册在默认RunLoop模式下,同样会被阻塞不执行
解决方案
- 第一步:确保所有UI操作严格在主队列执行,错误的队列调度会导致刷新不生效,正确写法如下
Objective-C版本:
Swift版本:// 收到Socket数据先更新数据源数组,再刷新UI self.dataArray = newDataFromSocket; dispatch_async(dispatch_get_main_queue(), ^{ [self.tableView reloadData]; });// 先更新数据源 self.dataArray = newDataFromSocket DispatchQueue.main.async { self.tableView.reloadData() } - 第二步:将Socket的运行模式设置为通用模式,保证滑动时也能正常收到数据回调,以常用的CocoaAsyncSocket库为例:
// 初始化Socket后设置运行模式 self.socket.runLoopModes = [NSRunLoopCommonModes]; - 第三步:如果上述操作仍未生效,可以将刷新任务显式指定到通用RunLoop模式下执行:
[self performSelector:@selector(reloadTableView) onThread:[NSThread mainThread] withObject:nil waitUntilDone:NO modes:@[NSRunLoopCommonModes]]; - (void)reloadTableView { [self.tableView reloadData]; } - 可选优化:如果数据更新频率高于1次/秒,建议增加防抖逻辑:收到新数据后先更新数据源、标记需要刷新的状态,每1-2秒统一调用一次reloadData,避免频繁刷新导致滑动卡顿。
内容的提问来源于stack exchange,提问作者Nawin Poolsawad
相关产品推荐
相关产品推荐

