In my iOS application, I have a protocol extension that is similar to the following:
protocol ViewControllerBase: UIViewController {
}
extension ViewControllerBase {
func showItem(itemID: Int) {
Task {
await loadItemDetails(itemID)
let itemDetailsViewController = ItemDetailsViewController(style: .grouped)
present(itemDetailsViewController, animated: true)
}
}
func loadItemDetails(_ itemID: Int) async {
}
}
I'm using a protocol extension so that all of the view controllers that implement ViewControllerBase
will inherit the showItem()
method. ItemDetailsViewController
is defined as follows:
class ItemDetailsViewController: UITableViewController {
}
The call to loadItemDetails()
compiles fine, but the calls to the ItemDetailsViewController
initializer and present()
method produce the following compiler error:
Expression is 'async' but is not marked with 'await'
This doesn't make sense to me, since the initializer and method are not asynchronous. Further, I'm using the same pattern elsewhere without issue. For example, if I convert ViewControllerBase
to a class, it compiles fine:
class ViewControllerBase: UIViewController {
func showItem(itemID: Int) {
Task {
await loadItemDetails(itemID)
let itemDetailsViewController = ItemDetailsViewController(style: .grouped)
present(itemDetailsViewController, animated: true)
}
}
func loadItemDetails(_ itemID: Int) async {
}
}
It seems to be related to UIKit specifically, because this code also compiles fine:
class ItemDetails {
}
protocol Base {
}
extension Base {
func showItem(itemID: Int) {
Task {
await loadItemDetails(itemID)
let itemDetails = ItemDetails()
present(itemDetails)
}
}
func loadItemDetails(_ itemID: Int) async {
}
func present(_ itemDetails: ItemDetails) {
}
}
Is there a reason this code would not be allowed in a protocol extension, or might this be a bug in the Swift compiler?
CodePudding user response:
Mark your method as @MainActor
:
extension ViewControllerBase {
@MainActor func showItem(itemID: Int) {
Task {
await loadItemDetails(itemID)
let itemDetailsViewController = ItemDetailsViewController(style: .grouped)
present(itemDetailsViewController, animated: true)
}
}
func loadItemDetails(_ itemID: Int) async {
}
}