2

In SwiftUI, I am trying to call an async function(which is for loading images that is picked by ImagePicker) by using .onChange. I got "'async' call in a function that does not support concurrency" error. If I make function sync and remove "Task {@MainActor in" section, then it runs but I get some purple errors during loading images which I do not want.

Is it possible to use .onChange to call async function?

func loadImage() async {
    Task { @MainActor in
        guard let inputImage = inputImage else {
            loadingState = .failed
            return
        }
        jpegData = inputImage.jpegData(compressionQuality: 0.8)!
        image = Image(uiImage: inputImage)
        loadingState = .loaded
    }
}

I try to call the function as below;

.onChange (of: addPersonViewModel.inputImage, perform: { _ in addPersonViewModel.loadImage() })

If I make function sync and remove "Task {@MainActor in" section, then it runs but I get some purple errors during loading images which I do not want.

1
  • Hi @Gorkem, and welcome to Stack Overflow. Please add sample code that demonstrates the problem, that can be run by someone trying to solve it. In SwiftUI, ideally a struct ContentView that can be pasted into Xcode. Please read minimal reproducible example Commented Jan 17, 2023 at 9:58

1 Answer 1

7

Instead of

.onChange (of: addPersonViewModel.inputImage, perform: { _ in addPersonViewModel.loadImage() })

Use

.task(id:addPersonViewModel.inputImage){
 await addPersonViewModel.loadImage() }

You will have to make a slight modification to your function

func loadImage() async {

    guard let inputImage = inputImage else {
        loadingState = .failed
        return
    }
    jpegData = inputImage.jpegData(compressionQuality: 0.8)!
    image = Image(uiImage: inputImage)
    loadingState = .loaded

}

That floating Task inside a function is not a good practice.

Sign up to request clarification or add additional context in comments.

5 Comments

I tried and get "Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates." purple error.
@GorkemTuran put “@MainActor” on the ViewModel (above the class declaration). It’s purpose is to update the view so it should always be wrapped.
task(id:) is good, now just remove the view model
@malhal we have discussed the whole View Model thing before, I don't mind if people use it. Have you tried coding something with strict concurrency?, it will become nearly impossible to code without an additional class or struct if the warnings that are appearing now stay. SwiftUi wrappers like State and Binding make SwiftUI Views non-Sendable it is quite a disaster.
@GorkemTuran if I answered your question do you mind clicking on the green checkmark to accept the answer?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.