Swift Flow中UITableView隐藏/显示与重载时序不一致问题咨询
问题根因
- 你对UIKit的渲染机制理解有偏差:所有UI属性(比如
isHidden)的修改不会立刻触发屏幕渲染,只是标记为「待更新」,系统会等到当前主线程RunLoop的绘制周期才会批量提交给渲染服务。你在设置隐藏后,后续的UserDefaults读写、导航栏按钮配置、以及主队列async闭包里的同步逻辑如果耗时较长,都会卡住主线程,推迟隐藏状态的渲染时机,甚至会出现「隐藏」和「后续的显示」操作被合并,导致你完全看不到隐藏的过程。 - 你当前把数据解析、表格重载逻辑全部放在主队列同步执行,如果
finalParse涉及大量数据处理,会直接阻塞主线程,进一步放大时序问题。
修复方案
- 拆分耗时逻辑到后台线程,避免阻塞主线程UI更新
- 确保隐藏状态渲染完成后再执行数据加载逻辑,可以用极小的延时保证当前RunLoop的UI更新先完成
- 所有UI相关操作(包括表格重载、显示隐藏)必须放回主线程执行
修改后参考代码
@objc func sportsChange() { reloadTab = 1 spinnerView.isHidden = false self.rosterTable.isHidden = true self.searchBar.isHidden = true // 先处理不需要耗时的UI配置和偏好存储 if(selectedSport == fbSport){ theUserDefaults.set(bbSport, forKey: "sportDefault") selectedSport = theUserDefaults.string(forKey: "sportDefault") sportLogo = sportBbLogo theUserDefaults.set(sportBbLogo, forKey: "sportLogo") } else if(selectedSport == bbSport){ theUserDefaults.set(fbSport, forKey: "sportDefault") selectedSport = theUserDefaults.string(forKey: "sportDefault") theUserDefaults.set(sportFbLogo, forKey: "sportLogo") sportLogo = sportFbLogo } let sportImageSet = UIImage(named: sportLogo!) sportsIcon.setImage(sportImageSet , for: .normal) let sportButton = UIBarButtonItem(customView: sportsIcon) let currWidth = sportButton.customView?.widthAnchor.constraint(equalToConstant: 30) currWidth?.isActive = true let currHeight = sportButton.customView?.heightAnchor.constraint(equalToConstant: 30) currHeight?.isActive = true sportsIcon.addTarget(self, action: #selector(sportsChange), for: .touchUpInside) // 极小延时保证当前UI更新(隐藏表格、搜索栏)先渲染完成 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { // 耗时的URL拼接、数据解析丢到后台队列 DispatchQueue.global().async { self.rosterUrl = getRosterUrl(server: server, tid: teamid, yr: currentYearStr, sp: selectedSport!) self.finalParse(getTheUrl: self.rosterUrl) // 表格重载、UI显示切回主线程 DispatchQueue.main.async { self.rosterTable.reloadWithAnimation() self.rosterTable.isHidden = false self.searchBar.isHidden = false self.spinnerView.isHidden = true } } } }
额外注意点
- 不要在主线程执行任何非UI的耗时操作,包括大量数据解析、文件读写、网络请求(看起来你当前的
finalParse是同步请求/解析,非常容易卡主线程) - 避免强制解包
sportLogo!这类可选值,增加判空逻辑减少崩溃风险
内容的提问来源于stack exchange,提问作者tjberte
相关产品推荐
相关产品推荐

