You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:49:46