iOS 13下UITableView数据源切换后UI未更新的技术咨询
这个iOS 13特有的问题我之前也碰到过好几次,结合你描述的症状——数据源已经切换正确、DataSource方法也调用了正确的数据源,但UI依然停留在搜索结果——大概率是iOS 13对UISearchController的生命周期或状态同步机制做了调整导致的。下面是几个最可能的原因和对应的解决办法:
1. 取消按钮的处理时机与isActive状态不同步
iOS 13之后,searchBarCancelButtonClicked:的调用时机和searchController.isActive的状态变化顺序和iOS 12不一样了。你可能在切换数据源时,UISearchController还没完全退出活跃状态,导致TableView的刷新被系统的内部状态覆盖。
解决办法:不要直接在searchBarCancelButtonClicked:里执行切换操作,而是先主动设置isActive = false,然后在主队列异步执行数据源切换和刷新,确保状态完全更新:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchController.isActive = false DispatchQueue.main.async { self.currentDataSource = self.mainDataSource self.tableView.reloadData() } }
也可以通过KVO监听isActive属性的变化,当它变为false时再处理数据源切换,这样能更精准地捕捉状态变更时机。
2. reloadData未触发有效UI更新
虽然你调用了tableView.reloadData(),但iOS 13里TableView和UISearchController的关联状态可能导致刷新被忽略。可以尝试更强制的刷新方式:
// 先重置数据源引用,确保TableView重新确认数据源 self.tableView.dataSource = nil self.tableView.dataSource = self // 再执行刷新 self.tableView.reloadData() // 额外触发一次布局刷新 self.tableView.setNeedsLayout() self.tableView.layoutIfNeeded()
这种方式能强制TableView重新绑定数据源并刷新UI。
3. 搜索数据源的残留引用或逻辑疏漏
虽然你确认DataSource方法调用了正确的数据源,但还是建议在cellForRowAt方法里加个打印日志,确认每次返回的cell内容确实来自主数据源——有时候代码里的条件分支可能存在疏漏,比如某个地方不小心复用了搜索数据源的变量。另外检查搜索数据源是否被其他对象持有,导致切换后仍有残留数据被读取。
4. obscuresBackgroundDuringPresentation属性影响
iOS 13中UISearchController的obscuresBackgroundDuringPresentation默认值和iOS 12不同,这个属性控制搜索时背景是否被模糊遮挡。如果设置为true,可能在取消搜索时背景视图的刷新存在延迟。可以尝试将其设置为false:
searchController.obscuresBackgroundDuringPresentation = false
这能避免背景视图的状态干扰TableView的刷新。
内容的提问来源于stack exchange,提问作者Zsolt

