How to return variable defined in Task in Swift
Asked Answered
C

1

6

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
}
Commandeer answered 11/5, 2022 at 9:23 Comment(4)
How and where is func newArtist( used?Chandra
How about func newArtist(name: ...) async -> Artist and put it into a Task on the caller side?Rozamond
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.Dehumanize
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.Commandeer
L
4

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)
    }
}
Ladle answered 11/5, 2022 at 9:53 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.