If I declare this protocol and model:
protocol SubScene: UIViewController {
func doSomething()
}
struct Model {
let subScene: SubScene
func longCalculation() async {
// Some long-running operation...
await subScene.doSomething()
}
}
class MyVC: UIViewController, SubScene {
func doSomething() {
performSegue(withIdentifier: "segue", sender: nil)
}
}
let myVC = MyVC()
let model = Model(subScene: myVC)
Task.detached {
await model.longCalculation()
}
I've declared a protocol that is restricted to UIViewController
, and a model which calls the protocol's doSomething()
method from an async context. Since UIViewController
is a MainActor
, my expectation is that doSomething()
should get called on the main thread.
However, it does not. In fact the await
keyword results in a warning from Swift that it is not calling an async method. And empirical testing shows that doSomething()
will often end up being called on some other thread.
I can fix that by annotating doSomething()
as a MainActor
:
protocol SubScene: UIViewController {
@MainActor func doSomething()
}
This gets rid of the Swift warning and also results in doSomething()
getting called on the correct thread.
Is this the correct approach, or is there another way that I could be doing this that avoids having to sprinkle all of my protocol methods with @MainActor
?
CodePudding user response:
You could, alternatively, mark the entire protocol as @MainActor
, e.g.,
@MainActor protocol SubScene: AnyObject {
func doSomething()
}
That avoids the need to declare each conforming method individually.