fix(helper): box XPC reply closure to cross @Sendable boundary

@objc 协议 SystemProxyHelperControlling 里 reply 参数无法标注 @Sendable,
直接被 queue.async 的 @Sendable 闭包捕获即产生并发警告。装箱为
@unchecked Sendable 后跨过边界:XPC 运行时生成的应答块线程安全且恰好
调用一次,引擎在串行工作队列上调用它本就是既有设计,行为不变。
This commit is contained in:
Qiu Yuzhou
2026-10-03 03:36:39 +08:00
parent 1ce96da710
commit 9530af2a19
@@ -34,14 +34,16 @@ final class SystemProxyHelperEngine: NSObject, SystemProxyHelperControlling {
}
func apply(_ payload: Data, withReply reply: @escaping (Data) -> Void) {
queue.async { [perform] in
let reply = ReplyBox(reply)
queue.async { [perform, reply] in
let request = Result { try SystemProxyHelperWire.decodeConfiguration(payload) }
reply(Self.responseData(request: request.map { .apply($0) }, perform: perform))
}
}
func clear(withReply reply: @escaping (Data) -> Void) {
queue.async { [perform] in
let reply = ReplyBox(reply)
queue.async { [perform, reply] in
reply(Self.responseData(request: .success(.clear), perform: perform))
}
}
@@ -72,3 +74,18 @@ final class SystemProxyHelperEngine: NSObject, SystemProxyHelperControlling {
}
}
}
/// XPC 应答闭包的 Sendable 桥。@objc 协议里 reply 参数无法标注 @Sendable,
/// 但 XPC 运行时生成的应答块线程安全且恰好调用一次,引擎在串行工作队列上
/// 调用它;装箱只为跨过 queue.async 的 @Sendable 边界。
private final class ReplyBox: @unchecked Sendable {
private let reply: (Data) -> Void
init(_ reply: @escaping (Data) -> Void) {
self.reply = reply
}
func callAsFunction(_ data: Data) {
reply(data)
}
}