I have a ViewModel and I added the @MainActor to it, but there is a function in the viewModel where it starts to fetch data. I wanted to run this method on the background thread to keep the mainActor available, after trying the only way where I managed to remove the warning in the strict mode and also run function in the background is by conforming the viewModel to sendable type. My question is the following is there a way to run a method in a class annotated with @MainActor off the mainThread ?
@Observable
@MainActor
final class LinkPreviewViewModel {
var isLoading: Bool = true
var isThereError: Bool = false
var isShareSheetPresented: Bool = false
var linkMetadata: LPLinkMetadata?
var url: URL?
init(url: URL?) {
self.url = url
}
}
extension LinkPreviewViewModel {
func loadMetadata() async {
do {
guard let url = url else { return }
isLoading.toggle()
isThereError = false
let metadataProvider = LPMetadataProvider()
let metaData = try await metadataProvider.startFetchingMetadata(for: url) // runs // on the mainActor
linkMetadata = metaData
isLoading.toggle()
} catch {
isLoading = false
isThereError = true
}
}
}
sendable solution :
@Observable
//@MainActor
final class LinkPreviewViewModel: @unchecked Sendable {
var isLoading: Bool = true
var isThereError: Bool = false
var isShareSheetPresented: Bool = false
var linkMetadata: LPLinkMetadata?
var url: URL?
init(url: URL?) {
self.url = url
}
}
extension LinkPreviewViewModel {
func loadMetadata() async {
do {
guard let url = url else { return }
await isLoading.asyncToggle()
await isThereError.asyncSet(false)
let metadataProvider = LPMetadataProvider()
let metaData = try await metadataProvider.startFetchingMetadata(for: url) // runs // in the background
await setLinkMetadata(metaData)
await isLoading.asyncToggle()
} catch {
await isLoading.asyncSet(false)
await isThereError.asyncSet(false)
}
}
}
@MainActor
extension LinkPreviewViewModel {
func setLinkMetadata(_ metadata: LPLinkMetadata) async {
linkMetadata = metadata
}
}