I have seen code like this
func connectVCAndVM() {
// Setting up a closure to be called when data in the viewModel changes
viewModel.dataChanged = { [weak self] in
Task { @MainActor in
// Reloading the tableView when data changes
self?.tableView.reloadData()
}
}
}
Do we need "@MainActor in" here? If the task is written inside viewcontroller, wouldn't the task automatically be executed in main thread due to context inheritance? I am learning about Actors so consider this as a newbie doubt.
It depends upon how the view model was written and how dataChanged
was defined.
A view model’s entire purpose is to integrate with a view, and all view interaction must be done from the main thread, so we frequently write our view models so that the closures are invoked from the main thread only (explicitly, so you don’t need to do stuff like you’ve got here).
Personally, I would be inclined to define the closure as such:
@MainActor
class ViewModel {
var dataChanged: (@Sendable @MainActor () -> Void)?
…
}
That way, both the view and the view model understand that this closure will be invoked on the main actor.
Then the view controller can simply:
func connectVCAndVM() {
// Setting up a closure to be called when data in the viewModel changes
viewModel.dataChanged = { [weak self] in
self?.tableView.reloadData()
}
}