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

Swift中使用带unownedExecutor的GlobalActor触发EXC_BAD_ACCESS问题

自定义GlobalActor触发EXC_BAD_ACCESS错误的排查与修复

作为Swift新手,我尝试参照Apple文档实现一个基于unownedExecutor的最小化GlobalActor,让它在专用线程上运行。编写测试代码后,点击Test按钮时,在Task.detached语句处触发了EXC_BAD_ACCESS错误,对比网上示例没发现代码差异,请求排查原因。

原实现代码

GlobalActor实现

@globalActor actor BackendActor: GlobalActor {
    static let shared = BackendActor()
    nonisolated let unownedExecutor: UnownedSerialExecutor = Executor().asUnownedSerialExecutor()
    
    final private class Executor: SerialExecutor {
        private let dispatcher = DispatchQueue(label: "BackendQueue")
        
        internal func enqueue(_ job: UnownedJob) {
            self.dispatcher.async {
                job.runSynchronously(on: sharedUnownedExecutor)
            }
        }
        
        internal func asUnownedSerialExecutor() -> UnownedSerialExecutor {
            UnownedSerialExecutor(ordinary: self)
        }
    }
}

测试代码

import SwiftUI

@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct ContentView: View {
    var body: some View {
        Button("Test") {
            Task.detached { @BackendActor in
                print("Ok")
            }
        }
    }
}

错误原因

问题出在Executor实例的生命周期上:你直接在unownedExecutor的初始化语句中创建Executor()并转换为UnownedSerialExecutor,但**UnownedSerialExecutor对Executor实例的引用是无主(unowned)的**,没有强引用持有这个Executor对象。当初始化完成后,Executor实例会被立即释放,后续尝试访问它时就会触发EXC_BAD_ACCESS错误。

另外原代码中job.runSynchronously(on: sharedUnownedExecutor)存在未定义标识符的问题,这也是潜在的崩溃诱因。

修复方案

需要在BackendActor中添加一个强引用属性来持有Executor实例,确保它不会被提前释放,同时修正runSynchronously的参数。修改后的代码如下:

@globalActor actor BackendActor: GlobalActor {
    static let shared = BackendActor()
    // 强引用持有Executor实例,避免被提前释放
    nonisolated private let executor = Executor()
    nonisolated let unownedExecutor: UnownedSerialExecutor
    
    init() {
        // 通过持有的executor创建UnownedSerialExecutor
        self.unownedExecutor = executor.asUnownedSerialExecutor()
    }
    
    final private class Executor: SerialExecutor {
        private let dispatcher = DispatchQueue(label: "BackendQueue")
        
        internal func enqueue(_ job: UnownedJob) {
            self.dispatcher.async {
                // 使用当前Executor的无主引用
                job.runSynchronously(on: self.asUnownedSerialExecutor())
            }
        }
        
        internal func asUnownedSerialExecutor() -> UnownedSerialExecutor {
            UnownedSerialExecutor(ordinary: self)
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 01:52:35