NS_SWIFT_UI_ACTOR 注释不适用于基于回调的 Objective-C 方法的异步变体

发布于 2025-01-19 20:02:26 字数 1079 浏览 5 评论 0原文

在Objective-C中,我们可以使用NS_SWIFT_UI_ACTOR指示应在主演员上执行方法或整个类(就像我们在Swift中使用@mainactor一样)。这是正确起作用的,因为当调用一种从主演员外部返回值的方法(使用Task.tected.tected.thecked.staberct Priarity)时,编译器迫使我们使用“等待”来调用它(允许“ Actor Switch”)和,在运行时,我可以看到该代码是在主线程上执行的。

但是,当在同一类调用基于回调的方法时(该方法会自动获得“导入”异步变体,如说明在这里)NS_SWIFT_UI_ACTOR似乎无法正常工作,并且代码在后台线程上执行。

NS_SWIFT_UI_ACTOR
@interface ObjcClass : NSObject
- (NSString *)method1;
- (void)method2WithCompletion: (void (^)(NSString * _Nonnull))completion;
@end
Task.detached(priority: .background) {
    let objcInstance = ObjcClass()
    print(await objcInstance.method1())   <----- this is called on the main thread
    print(await objcInstance.method2())   <----- this is called on a bg thread
}

In Objective-c we can use NS_SWIFT_UI_ACTOR to indicate that a method or a whole class should be executed on the main actor (as we would do with @MainActor in Swift). This works correctly since, when invoking a method which returns a value from outside the main actor (using a Task.detached with background priority), the compiler forces us to call it using "await" (to allow for "actor switch") and, at runtime, I can see that the code is executed on the main thread.

However, when calling a callback based method on the same class (which gets an automatically "imported" async variant, as explained here) the NS_SWIFT_UI_ACTOR seems not working properly, and the code is executed on a background thread.

NS_SWIFT_UI_ACTOR
@interface ObjcClass : NSObject
- (NSString *)method1;
- (void)method2WithCompletion: (void (^)(NSString * _Nonnull))completion;
@end
Task.detached(priority: .background) {
    let objcInstance = ObjcClass()
    print(await objcInstance.method1())   <----- this is called on the main thread
    print(await objcInstance.method2())   <----- this is called on a bg thread
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

等往事风中吹 2025-01-26 20:02:26

虽然我了解您的期望是什么,但我现在不认为演员的实施方式可以解决此问题。 Swift中的参与者是重新进入的,这意味着每当您调用Actor的方法/Actor任务中的任何async方法时,Actor都会暂停当前任务,直到方法返回并开始处理其他任务为止。这种重新进入行为很重要,因为它不仅在执行长期任务时锁定演员。

让我们以mainactor隔离async方法的示例:

func test() async {
    callSync() // Runs on MainActor
    await callAsync() // Suspends to process other task, waits for return to resume executing on MainActor
    callSync() // Runs on MainActor
}

但是由于Swift无法从目标C async方法中推断出哪一部分应在MainActor以及哪个部分演员只能暂停当前任务以处理其他任务,整个async方法不隔离到演员。

但是,当前有一些建议允许定制演员的重新输入,以便您可以在Actor上执行整个OBJC async方法。

While I understand what your expectation is I don't think as of now the way actor is implemented there is any way to resolve this. Actors in swift are reentrant, which means whenever you invoke any async method inside actor's method/actor task, actor suspends the current task until the method returns and starts processing other tasks. This reentrancy behavior is important as it doesn't just lock the actor when executing a long-running task.

Let's take an example of a MainActor isolated async method:

func test() async {
    callSync() // Runs on MainActor
    await callAsync() // Suspends to process other task, waits for return to resume executing on MainActor
    callSync() // Runs on MainActor
}

But since swift can't infer from an objective c async method which part should run on MainActor and for which part actor can just suspend the current task to process other tasks, the entire async method isn't isolated to the actor.

However, there are proposals currently to allow customizing an actor's reentrancy so you might be able to execute the entire objc async method on the actor.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文