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

iOS Swift中Semaphore使用崩溃求助:视图释放后回调崩溃

问题分析与解决方案

你的代码用信号量实现了异步任务顺序执行,但存在两个核心问题:

  1. 如果在主线程调用semaphore.wait(),会直接阻塞主线程导致界面卡死,这本身就是错误用法;
  2. 页面销毁后,回调仍持有已释放的对象(或信号量),触发时会引发崩溃——信号量本身没有“释放”概念,问题根源是任务生命周期未与页面绑定。

下面给出几种更安全的替代方案:


方案一:串行队列 + 链式异步调用

用串行队列天然的顺序执行特性,结合[weak self]避免循环引用,页面销毁后后续任务会自动终止。

// 定义私有串行队列
private let taskSerialQueue = DispatchQueue(label: "com.your.app.task.queue")

// 启动任务链
func startSequentialTasks() {
    taskSerialQueue.async { [weak self] in
        self?.performFirstTask {
            self?.taskSerialQueue.async {
                self?.performSecondTask {
                    self?.taskSerialQueue.async {
                        self?.performThirdTask {
                            // 所有任务完成后的逻辑
                        }
                    }
                }
            }
        }
    }
}

方案二:OperationQueue 管理任务(推荐)

通过设置最大并发数为1实现顺序执行,还支持主动取消任务,适配页面销毁场景。

第一步:自定义异步 Operation(处理异步任务)

系统默认的BlockOperation不支持异步任务,需要自定义:

class AsyncOperation: Operation {
    private enum State: String {
        case ready, executing, finished
    }
    
    private let asyncTask: (@escaping () -> Void) -> Void
    private var currentState: State = .ready {
        willSet {
            willChangeValue(forKey: newValue.rawValue)
            willChangeValue(forKey: currentState.rawValue)
        }
        didSet {
            didChangeValue(forKey: oldValue.rawValue)
            didChangeValue(forKey: currentState.rawValue)
        }
    }
    
    override var isReady: Bool { super.isReady && currentState == .ready }
    override var isExecuting: Bool { currentState == .executing }
    override var isFinished: Bool { currentState == .finished }
    override var isAsynchronous: Bool { true }
    
    init(task: @escaping (@escaping () -> Void) -> Void) {
        self.asyncTask = task
        super.init()
    }
    
    override func start() {
        guard !isCancelled else {
            currentState = .finished
            return
        }
        currentState = .executing
        asyncTask { [weak self] in
            guard let self = self, !self.isCancelled else { return }
            self.currentState = .finished
        }
    }
}

第二步:配置任务队列与依赖

private let operationQueue = OperationQueue()

func setupSequentialTasks() {
    operationQueue.maxConcurrentOperationCount = 1
    
    // 创建三个异步任务
    let firstTask = AsyncOperation { [weak self] completion in
        self?.performFirstTask {
            completion()
        }
    }
    
    let secondTask = AsyncOperation { [weak self] completion in
        self?.performSecondTask {
            completion()
        }
    }
    
    let thirdTask = AsyncOperation { [weak self] completion in
        self?.performThirdTask {
            completion()
        }
    }
    
    // 设置任务依赖:先执行first,再second,最后third
    secondTask.addDependency(firstTask)
    thirdTask.addDependency(secondTask)
    
    // 添加到队列执行
    operationQueue.addOperations([firstTask, secondTask, thirdTask], waitUntilFinished: false)
}

// 页面销毁时取消所有未完成任务
deinit {
    operationQueue.cancelAllOperations()
}

方案三:信号量的安全改造(不推荐)

如果一定要用信号量,必须在后台线程执行wait操作,同时在页面销毁时手动释放阻塞的线程:

private var semaphore: DispatchSemaphore? = DispatchSemaphore(value: 1)
private let backgroundQueue = DispatchQueue(label: "com.your.app.semaphore.queue")

func startTasksWithSemaphore() {
    backgroundQueue.async { [weak self] in
        guard let semaphore = self?.semaphore else { return }
        
        semaphore.wait()
        self?.performFirstTask {
            semaphore.signal()
        }
        
        semaphore.wait()
        self?.performSecondTask {
            semaphore.signal()
        }
        
        semaphore.wait()
        self?.performThirdTask {
            semaphore.signal()
        }
    }
}

// 页面销毁时释放所有可能的阻塞
deinit {
    // 最多3次wait,所以signal3次确保线程被释放
    semaphore?.signal()
    semaphore?.signal()
    semaphore?.signal()
    semaphore = nil
}

这种方式风险较高:无法准确判断当前阻塞的wait次数,容易出现信号量值异常,仅作为应急方案。


内容的提问来源于stack exchange,提问作者MobX

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 13:42:22