UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Using async / await with 'remote' functions

Forums > SwiftUI

I am fiddling with the MusicKit framework and retrieving album and song information from Apple Music using the framework. The framework has built in capabilities to deal with async / await, so you can for example request info through a call like var searchRequest = MusicCatalogSearchRequest(term: query, types: [Album.self, Song.self]) When I wrap this call in a function named query(searchText:) within the same SwiftUI file I am calling it from, with all logic to handle its responses, it all works fine; I see results coming in into my list in the UI. I've defined the function btw using @MainActor as per the example code from Apple.

However, as I want to use this search function across more of the UI, I moved it into a class called MusicKitAPI, of which I create a static instance and which I can then call using MusicKitAPI.shared.search(searchText:). Again, annotated the function with @MainActor but when calling this function from the UI, I see that the UI appears before the call returns its results. Calling the function a second time I see the results from the first call, etc.

The main question I have is how can I make remote functions I define and which are calling asynchronous functionality, behave properly when called from the file controlling the UI. Should I make the function itself async, or...?

3      

Answering my own question....

  1. Create a generic RemoteMusicService class inheriting from ObservableObject.
  2. Define a @Published variable named musicEntries containing the results of a search function using the MusicKit API's.
  3. Define the search(query: String) function itself (see MusicKit example on Apple's developer site).
  4. In the SwiftUI view that needs to display results of the search, define a @StateObject based on the RemoteMusicService class, e.g. @StateObject var remoteMusicService = RemoteMusicService().
  5. Call the search function from the view whenever required, e.g. remoteMusicService.search(query: searchText).
  6. Update the list in the view by referring to the @Published variable from the class, e.g. ForEach(remoteMusicService.musicEntries, ...)

Don't forget to add @MainActor on top of the RemoteMusicService class, otherwise you will get a 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 warning when running your code.

3      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.