Swift替代Bool实现函数互斥执行的方案咨询
替代Bool变量的Swift解决方案
嘿,这个场景我太熟悉了——用普通Bool变量确实容易踩线程安全的坑,尤其是在像didReceiveMemoryWarning这种系统回调里调用函数的时候。给你几个更可靠的替代方案,解决竞态条件的同时满足“仅当未执行时才运行”的需求:
1. 原子布尔属性(线程安全的Bool)
普通Bool在多线程环境下的读写不是原子操作,可能导致状态判断错误。我们可以封装一个线程安全的原子Bool,用串行队列来同步所有访问:
class AtomicBool { private let syncQueue = DispatchQueue(label: "com.yourapp.atomic.bool") private var _isActive = false var isActive: Bool { get { syncQueue.sync { _isActive } } set { syncQueue.sync { _isActive = newValue } } } // 可选:快速切换状态并返回新值 func toggle() -> Bool { syncQueue.sync { _isActive = !_isActive return _isActive } } } // 在你的类中使用 private let executionFlag = AtomicBool() func yourNavigationCleanupFunction() { // 先判断状态,再设置为执行中 guard !executionFlag.isActive, let currentNavVC = tabBarController.selectedViewController as? UINavigationController else { return } executionFlag.isActive = true // 你的业务逻辑 let firstVC = currentNavVC.viewControllers.first let lastVC = currentNavVC.viewControllers.last var targetControllers = [firstVC].compactMap { $0 } // 用compactMap避免nil if firstVC !== lastVC { targetControllers = [firstVC, lastVC].compactMap { $0 } } DispatchQueue.main.async { [weak self] in currentNavVC.viewControllers = targetControllers // 执行完成后重置状态 self?.executionFlag.isActive = false } }
优点:完全线程安全,用法和普通Bool几乎一致,适合大多数场景。
2. 轻量锁(NSLock/os_unfair_lock)
通过手动加锁来保护状态变量的读写,避免竞态条件。os_unfair_lock比NSLock更轻量,适合简单的互斥场景:
import os.lock // 用os_unfair_lock实现轻量互斥 private var executionLock = os_unfair_lock_s() private var isExecuting = false func yourNavigationCleanupFunction() { os_unfair_lock_lock(&executionLock) let shouldExecute = !isExecuting if shouldExecute { isExecuting = true } os_unfair_lock_unlock(&executionLock) guard shouldExecute, let currentNavVC = tabBarController.selectedViewController as? UINavigationController else { return } // 业务逻辑... let firstVC = currentNavVC.viewControllers.first let lastVC = currentNavVC.viewControllers.last var targetControllers = [firstVC].compactMap { $0 } if firstVC !== lastVC { targetControllers = [firstVC, lastVC].compactMap { $0 } } DispatchQueue.main.async { [weak self] in currentNavVC.viewControllers = targetControllers // 执行完成后解锁状态 os_unfair_lock_lock(&self!.executionLock) self!.isExecuting = false os_unfair_lock_unlock(&self!.executionLock) } }
优点:性能好,适合对性能敏感的场景;注意:一定要保证锁的成对调用,避免死锁。
3. DispatchWorkItem 跟踪执行任务
直接用可选类型的DispatchWorkItem来保存当前正在执行的任务,通过判断任务是否存在来决定是否执行新任务:
private var currentWorkItem: DispatchWorkItem? func yourNavigationCleanupFunction() { guard currentWorkItem == nil, let currentNavVC = tabBarController.selectedViewController as? UINavigationController else { return } // 业务逻辑提前处理(避免在WorkItem中捕获过多变量) let firstVC = currentNavVC.viewControllers.first let lastVC = currentNavVC.viewControllers.last var targetControllers = [firstVC].compactMap { $0 } if firstVC !== lastVC { targetControllers = [firstVC, lastVC].compactMap { $0 } } // 创建工作项 let workItem = DispatchWorkItem { [weak self] in currentNavVC.viewControllers = targetControllers // 任务完成后清空引用 self?.currentWorkItem = nil } currentWorkItem = workItem DispatchQueue.main.async(execute: workItem) }
优点:不需要额外的状态变量,还支持任务取消(比如在内存警告时可以调用currentWorkItem?.cancel()),灵活性更高。
为什么DispatchSemaphore对你无效?
你之前尝试的DispatchSemaphore更适合“等待前一个任务完成再执行”的场景(阻塞式等待),而你的需求是“如果正在执行就直接返回”,所以Semaphore的用法和你的需求不匹配——如果用Semaphore,后续调用会被阻塞直到前一个任务完成,这显然不是你想要的效果。
最后,记得在didReceiveMemoryWarning中调用时,确保没有循环引用(比如用[weak self]捕获),避免内存泄漏。
内容的提问来源于stack exchange,提问作者udbhateja
相关产品推荐
相关产品推荐

