I'm currently working on a new iOS project.
To be up to date with the new concurrency from Swift I have switched the Strict concurrency checking
setting too "complete". This has of course sprung up lot's of warning and error that I was mostly able to fix.
Never the less there are a few cases that I can't figure out.
My project structure is a very commun MVVM pattern in Swift/SwiftUI.
Where my viewModels implement the ObservableObject
and Sendable
protocols.
They contain @Published
variables that are update internally to refresh my associated SwiftUI views.
My problem is that I have concurrency warnings on these @Published
variables and I can't figure out how to get rid of them except settings my viewmodels as @unchecked Sendable
, which is not really recommended.
Following is an example of a viewModel and it's associated warning:
final class HomeViewModel: ObservableObject, Sendable {
// The warning concerns this variable
@Published private(set) var pageState: PageState<HomePageModel> = .loading
private var reloadTask: Task<Void, Never>?
init() {
setUp()
}
deinit {
reloadTask?.cancel()
}
func fetchHomeContent() async {
if Task.isCancelled { return }
do {
XXXXX async execution happening here
try Task.checkCancellation()
let sortedSections = sections.sorted { $0.order < $1.order }
await updatePageStage(with: .loaded(HomePageModel(sections: sortedSections)))
} catch {
await updatePageStage(with: .error(error.localizedDescription))
}
}
func reloadData() {
reloadTask?.cancel()
reloadTask = Task { [weak self] in
await self?.fetchHomeContent()
}
}
}
private extension HomeViewModel {
@MainActor
func updatePageStage(with state: PageState<HomePageModel>) {
pageState = state
}
}
Warning
Stored property '_pageState' of 'Sendable'-conforming class 'HomeViewModel' is mutable
As you can see the warning is quite clear but I cannot seem to find a way to make it disappear.
nonisolated
is not supported on properties with property wrappers so that doesn't work.
Having a private(set)
also.
As you can see the function updatePageStage
is @MainActor
bounded and my HomeViewModel
is a @StateObject
making it also @MainActor
bounded through Swift implementation.
My question is simple: is there a way to remove this warning without using tricks like @unchecked Sendable
or setting explicitly the entire class as @MainActor
Thank you in advance for any tips.
When you use async/await you no longer need an object, it's simply:
The task is started when the underlying
UIView
appears and cancelled when it disappears. This simplifies async lifecycle management greatly. Also you can usetask(id: pageNumber)
to cancel and restart the task when the id param changes.