在 Swift 中将 GlobalActor 与 unownedExecutor 一起使用时的 EXC_BREAKPOINT

问题描述 投票:0回答:1

我对 Swift 比较陌生,并试图做一个最小的 GlobalActor 工作,应该在专用线程上运行代码,使用

unownedExecutor
中建议的 docs:

@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)
        }
    }
}

运行以下 MWE 时,

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")
            }
        }
    }
}

并按下按钮

Test
EXC_BAD_ACCESS
指令中会出现
Task.detached
错误。

我用网上可以找到的示例多次检查了我的

GlobalActor
的代码,但我没有发现它可能无法工作的任何区别。

swift
1个回答
0
投票

正如

unownedExecutor
的 XCode 中的文档所建议的,此属性对于 actor 实例必须相同,并且 actor 必须保持执行器处于活动状态,如您的代码中所示,我检查
Executor
是否已
deinit
所以发生了异常。

enter image description here

解决方案可以将 Excutor 实例保留为 actor 中的属性以使其保持活动状态:

@globalActor actor BackendActor {
    static let shared = BackendActor()
    fileprivate let executor = Executor()
    
    nonisolated var unownedExecutor: UnownedSerialExecutor {
        executor.asUnownedSerialExecutor()
    }
}

final private class Executor: SerialExecutor {
    private let dispatcher = DispatchQueue(label: "BackendQueue")
    
    static let shared = Executor()
    
    func enqueue(_ job: UnownedJob) {
        dispatcher.async {
            job.runSynchronously(on: self.asUnownedSerialExecutor())
        }
    }
    
    func asUnownedSerialExecutor() -> UnownedSerialExecutor {
        UnownedSerialExecutor(ordinary: self)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.