在指定了@MainActor
的Swift方法中,该方法调用withCheckedContinuation
并进行其他异步调用,似乎在@MainActor
线程上调用了withCheckedContinuation
,但其他异步调用并非如此.
这是巧合吗?
可以将以下代码放入XCode为您创建的默认iOS App的ContentView.swft中:
import SwiftUI
func printCurrentThread(_ label: String) {
print("\(label) called on \(Thread.current)")
}
class SomeNonThreadSafeLibrary {
func getFromServer(msg: String, completionHandler: @escaping (String) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
completionHandler(msg)
}
}
}
class AppController: ObservableObject {
@Published var something1: String = "not set"
@Published var something2: String = "not set"
var someNonThreadSafeLibrary: SomeNonThreadSafeLibrary? = SomeNonThreadSafeLibrary()
func someOtherAsyncFunction(calledFrom: String) async {
printCurrentThread("\(calledFrom) -> someOtherAsyncFunction")
}
func getSomethingAsynchronously() async -> String {
printCurrentThread("getSomethingAsynchronously")
await someOtherAsyncFunction(calledFrom: "getSomethingAsynchronously")
return await withCheckedContinuation { continuation in
printCurrentThread("getSomethingAsynchronously -> withCheckedContinuation")
do {
try Task.checkCancellation()
self.someNonThreadSafeLibrary?.getFromServer(msg: "getSomethingAsynchronously") { result in
printCurrentThread("getSomethingAsynchronously -> getFromServer closure")
continuation.resume(returning: result)
}
}
catch {}
}
}
@MainActor
func getSomethingAsynchronouslyWithMainActor() async -> String {
printCurrentThread("getSomethingAsynchronouslyWithMainActor")
await someOtherAsyncFunction(calledFrom: "getSomethingAsynchronouslyWithMainActor")
return await withCheckedContinuation { continuation in
printCurrentThread("getSomethingAsynchronouslyWithMainActor -> withCheckedContinuation")
do {
try Task.checkCancellation()
self.someNonThreadSafeLibrary?.getFromServer(msg: "getSomethingAsynchronouslyWithMainActorWithMainActor") { result in
printCurrentThread("getSomethingAsynchronouslyWithMainActor -> getFromServer closure")
continuation.resume(returning: result)
}
}
catch {}
}
}
@MainActor
func getValueForSomething() async {
something1 = await getSomethingAsynchronously()
}
@MainActor
func getValueForSomethingWithMainActor() async {
something2 = await getSomethingAsynchronouslyWithMainActor()
}
}
struct ContentView: View {
@StateObject private var appController = AppController()
var body: some View {
VStack {
Text("something1 is \(appController.something1)")
Text("something2 is \(appController.something2)")
}
.task {
await appController.getValueForSomething()
}
.task {
await appController.getValueForSomethingWithMainActor()
}
.padding()
}
}
代码的输出如下所示...
在线程1上调用带@MainActor
的函数,在任意线程上调用不带@MainActor
的函数,正如预期的那样:
getSomethingAsynchronouslyWithMainActor called on <_NSMainThread: 0x600001910400>{number = 1, name = main}
getSomethingAsynchronously called on <NSThread: 0x60000195c300>{number = 7, name = (null)}
然后,从这些方法中的每一个调用不做任何事情的函数someOtherAsyncFunction
,并且在两种情况下(即,在调用函数上具有或不具有@MainActor
),它在任意线程上被调用.这表明函数上的@MainActor
不会被其内部调用的函数继承:
getSomethingAsynchronously -> someOtherAsyncFunction called on <NSThread: 0x60000195c300>{number = 7, name = (null)}
getSomethingAsynchronouslyWithMainActor -> someOtherAsyncFunction called on <NSThread: 0x6000019582c0>{number = 6, name = (null)}
然而,在闭包为withCheckedContinuation
的特定情况下,当@MainActor
在调用函数上时,它似乎确实在线程1上运行:
getSomethingAsynchronously -> withCheckedContinuation called on <NSThread: 0x60000195c300>{number = 7, name = (null)}
getSomethingAsynchronouslyWithMainActor -> withCheckedContinuation called on <_NSMainThread: 0x600001910400>{number = 1, name = main}
所以...withCheckedContinuation
似乎通过它的调用函数在@MainActor
上运行,这只是一个巧合,还是故意的?为什么只有withCheckedContinuation
,而不是someOtherAsyncFunction
?
如果它是设计出来的,我从哪里可以获得关于它在哪里指定的更多信息?