多ViewController场景下UILabel无法更新的问题求助
问题根源:主线程被阻塞啦!
其实你遇到的UILabel不更新问题,和多ViewController架构完全没关系——罪魁祸首是你代码里的sleep()方法!
在bleepTestLevel1Start的while循环里,sleep(UInt32(bleep_time[i]))会直接卡住主线程。iOS的UI更新必须在主线程执行,而且只有当主线程空闲时才会刷新界面。你的循环+sleep让主线程全程忙个不停,根本抽不出时间去更新Label的显示——虽然你确实修改了bleepTestLevel1Level.text的数值,但界面要等整个循环跑完才会一次性刷新,自然看不到实时变化。
至于控制台的那个changing property contentsGravity in transform-only layer警告,和你的Label问题无关,就是个图层配置的小细节,暂时不用管它。
修复方案:用异步延迟代替sleep
我们需要用非阻塞的方式实现延迟逻辑,让主线程能空出来处理UI更新。这里推荐用DispatchQueue的异步延迟来重构你的代码:
@IBAction func bleepTestLevel1Start(_ sender: Any) { tracker = false let totalSteps = bleep_time.count // 递归处理每个测试步骤 func runStep(at index: Int) { // 所有步骤执行完毕就退出 guard index < totalSteps else { return } // 必须在主线程更新UI(显式指定更稳妥) DispatchQueue.main.async { let currentLevel = self.bleep_level[index] self.bleepTestLevel1Level.text = "\(currentLevel)" } // 播放蜂鸣声 playSaveSound() // 延迟指定时间后,执行下一个步骤 let delay = DispatchTime.now() + .seconds(bleep_time[index]) DispatchQueue.main.asyncAfter(deadline: delay) { self.runStep(at: index + 1) } } // 启动第一个步骤 runStep(at: 0) }
为什么这个方案能解决问题?
- 用递归+
asyncAfter代替了while循环和sleep,每个步骤的延迟不会阻塞主线程,主线程可以在等待期间正常刷新UI、响应用户操作。 - 显式在主线程更新UILabel,确保UI修改的时机正确。
- 完美还原了你需要的“播放蜂鸣→等待指定时长→进入下一级”的逻辑,而且全程不会卡住界面。
另外你提到单VC测试时能成功更新,大概率是因为当时的测试用例循环次数少、延迟时间短,主线程阻塞的时间不够明显,本质上如果用sleep,单VC场景下同样会出现Label不实时更新的问题哦。
内容的提问来源于stack exchange,提问作者Spicey04
相关产品推荐
相关产品推荐

