4

I have a class Artist, and below is a function to create a new artist and insert it to my library array. Because insertToArtists(artist:) is a asynchronous function, I have to wrap it in Task. But I also want my newArtist to return the artist just created.

My code is like below, but Xcode told me an error: No 'init' candidates produce the expected contextual result type 'Artist'

func newArtist(name: String, notes: String, artwork: NSImage?) -> Artist {
    Task {
        let artist = Artist(name: name, notes: notes, artwork: artwork)
        await insertToArtists(artist: artist)
        return artist
    }
}

But if I make my code like this below. It won't work right. It seems that it returns artist before it's been insertToArtist(artist:). How can I return artist after it's been inserted. I would appreciate your help.

func newArtist(name: String, notes: String, artwork: NSImage?) -> Artist {
    let artist = Artist(name: name, notes: notes, artwork: artwork)
    Task {
        await insertToArtists(artist: artist)
    }
    return artist
}
Yiming Designer
  • 423
  • 3
  • 10
  • How and where is `func newArtist(` used? – burnsi May 11 '22 at 09:35
  • How about `func newArtist(name: ...) async -> Artist` and put it into a `Task` on the caller side? – vadian May 11 '22 at 09:43
  • First possibility : you mark your newArtist as async and remove task. Second possibility : you add a closure that will be executed when insertToArtist is finished and that have the newArtist as parameter. – Ptit Xav May 11 '22 at 09:47
  • Thanks guys. It work properly. But I'm still worried. Because I'm going to call `func newArtist(name: ...) -> Artist` in another function `@MainActor func checkCreate()` which is used to update UI. If I use `newArtist(name) async -> Artist`, would it block main thread when some suspension occurred. – Yiming Designer May 11 '22 at 10:02

1 Answers1

3

Well, it would be useful to know how newArtist is used, but I believe you will need to make it async as well.

func newArtist(name: String, notes: String, artwork: NSImage?) async -> Artist {
    let artist = Artist(name: name, notes: notes, artwork: artwork)
    await insertToArtists(artist: artist)
    return artist
}

And then use Task where you are calling newArtist

func whereYouUseNewArtist() {
   //YourCode
   Task {
      //YourCode
      x = await newArtist(name: name, notes: notes, artwork: artwork)
      //YourCode
   }
//YourCode
}

If you need to update your UI with the result of newArtist, remember to do it in the main thread. You can do it by adding @MainActor to where you use it. Example:

let artistToShowOnUI: Artist
@MainActor func whereYouUseNewArtist() {
    Task {
       artistToShowOnUI = await newArtist(name: name, notes: notes, artwork: artwork)
    }
}
gggava
  • 206
  • 2
  • 9