Grand Central Dispatch代码应放置在何处以实现后台持续运行?
解决后台持续运行计数器并更新UI的问题
先聊聊你当前代码里几个需要注意的细节,再告诉你该把GCD代码放在哪里,以及更合理的实现方式:
一、现有代码的潜在问题
- UI更新必须在主线程:你在后台队列里直接修改
X.text,这会触发UIKit的线程安全问题,可能导致界面卡顿或异常——所有UI操作都必须在主线程执行。 sleep(1)阻塞线程:用sleep会持续占用后台队列的线程,既不高效还可能影响队列里其他任务的执行,不如用定时器更优雅。- 线程安全隐患:
globalValues的读写如果在多线程环境下进行,会出现竞态条件(比如多个线程同时修改Bits值),需要加锁保证数据安全。 - 无退出逻辑的循环:
while placeHolder == 0没有终止条件,就算用户离开当前页面,这个线程也会一直跑,白白浪费系统资源。
二、GCD代码的放置位置
你需要在页面显示时启动后台任务,页面消失时停止任务,这样既能保证用户查看时持续更新,又能避免无效的后台运行:
- 在视图控制器的
viewDidAppear(_:)方法里启动后台任务 - 在
viewDidDisappear(_:)方法里停止任务,释放相关资源
三、优化后的实现示例
给你的视图控制器添加定时器属性来控制任务启停,同时修复线程安全和UI更新的问题:
class YourViewController: UIViewController { // 用于控制后台任务的定时器 private var updateTimer: DispatchSourceTimer? // 假设你的计数标签是这个IBOutlet属性 @IBOutlet weak var BitCount: UILabel! override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) startBackgroundCounter() } override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) stopBackgroundCounter() } private func startBackgroundCounter() { // 创建后台并发队列 let queue = DispatchQueue(label: "queue.1", qos: .utility, attributes: .concurrent) // 创建每秒触发一次的定时器 updateTimer = DispatchSource.makeTimerSource(queue: queue) updateTimer?.schedule(deadline: .now(), repeating: .seconds(1)) updateTimer?.setEventHandler { [weak self] in guard let self = self else { return } // 给globalValues加锁,保证线程安全 objc_sync_enter(globalValues) var currentBits = globalValues.Bits if globalValues.bitsPerSecond != 0 { currentBits += 1 globalValues.Bits = currentBits print("Ran") // 保存到UserDefaults UserDefaults.standard.set(currentBits, forKey: "bits") } objc_sync_exit(globalValues) // 回到主线程更新UI DispatchQueue.main.async { self.BitCount.text = "\(currentBits)" } } updateTimer?.resume() } private func stopBackgroundCounter() { updateTimer?.cancel() updateTimer = nil } }
补充说明
- 用
DispatchSourceTimer代替while循环+sleep,更符合GCD的最佳实践,不会阻塞线程,资源占用更低。 - 用
objc_sync_enter/exit给globalValues加锁,你也可以用NSLock或者串行队列来处理线程安全问题。 [weak self]避免循环引用,确保视图控制器能正常被释放。- 在
viewDidDisappear里停止定时器,保证用户离开页面后任务立即终止,节省系统资源。
内容的提问来源于stack exchange,提问作者Trgrit Tjforce
相关产品推荐
相关产品推荐

