Consider this situation:
both the ViewModel and ViewController are compiled under Swift 6 with full concurrency checking enabled, while URLDataFetcher is still in Swift 5 mode.
I know that Swift 6 has some edge cases when calling Swift 5 modules, but the runtime behavior here really confuses me.
My most basic question is: why don’t test 1, 2, and 3 trigger an isolation assertion crash?
Are the isolation inference rules different between trailing closures and named closures?
Also, direct call the ViewModel method never crashes no matter what—unless I add @MainActor to the completionHandler parameter of its request method.
Am I missing some obvious piece of concurrency knowledge?
class ViewModel {
let fetcher = URLDataFetcher()
func request(url: String, completionHanlder: @escaping (String) -> Void) {
fetcher.request(url: url, completionHanlder: completionHanlder)
}
}
class ViewController: UIViewController {
let viewModel = ViewModel()
override func viewDidLoad() {
super.viewDidLoad()
// test 1: not crash, completionHanlder is not run in main thread
let completionHanlder1 = { (title: String) in
print(title)
}
viewModel.request(url: "", completionHanlder: completionHanlder1)
// test 2: not crash, completionHanlder is not run in main thread
viewModel.request(url: "", completionHanlder: { @MainActor (title: String) -> Void in
print(title)
})
// test3: not crash, completionHanlder is not run in main thread
let completionHanlder3 = { (title: String) -> Void in
print(title)
}
viewModel.fetcher.request(url: "", completionHanlder: completionHanlder3)
// test4: crash, diff isolation assert
let completionHanlder4 = { @MainActor (title: String) -> Void in
print(title)
}
viewModel.fetcher.request(url: "", completionHanlder: completionHanlder4)
// test5: crash, diff isolation assert
viewModel.fetcher.request(url: "") { (title: String) in
print(title)
}
}
}
public class URLDataFetcher {
public init() {}
public func request(url: String, completionHanlder: @escaping (String) -> Void) {
DispatchQueue.global().async {
completionHanlder("Hello, World!")
}
}
}