POP Demo
Head back to Xcode, where you’ll see how to use POP for the media shelf.
First, define a new protocol for the repository:
protocol MediaRepository {
associatedtype Item: MediaItem & Identifiable & View
func getItems() async throws -> [Item]
}
The protocol has a single function to retrieve the items. Just like the MediaCollection, the protocol uses generics with constrained types so it works for all MediaItems.
Next, create an implementation for the repository that returns some hard-coded video games:
struct VideoGameMediaRepository: MediaRepository {
func getItems() async throws -> [VideoGame] {
[arkhamKnight, tearsOfTheKingdom].shuffled()
}
}
The VideoGameMediaRepository implements the required getItems() and simply returns two hard-coded games. This approach is particularly useful in unit tests, eliminating the need for a database or an external API. VideoGamesMediaRepository uses shuffled() to make the order of the array random each time.
Next, update the items property from MediaCollectionView and add the repository:
let repository: any MediaRepository
@State var items: [T] = []
This adds a new property for the repository and makes the items array initially empty, since the data will now come from the repository. items is also annotated with @State, so the view updates when the array changes.
Next, update the live view to use the new repository. This will remove the errors:
let view = MediaCollectionView<VideoGame>(repository: VideoGameMediaRepository())
Rather than accepting an array of items for display, this now takes the repository as an argument, which serves as the source for the items.
Then, add a task to run when the SwiftUI view is created:
.task {
self.items = try! await repository.getItems() as! [T]
}
The task gets the items from the repository. You’re using a force try here for simplicity’s sake, but in your apps you should handle this correctly and display an appropriate error if it fails.
You’re also force casting the returned items. This is because the compiler can’t infer that the generic items from the repository match the generic requirements on the View. Since you know they’re the same here, this is safe to do.
Finally, add a pull to refresh action to the list, so you can reload the items when you want:
.refreshable {
self.items = try! await repository.getItems() as! [T]
}
This retrieves data from the repository, similar to the initial task that loads the view.
Run the playground. You’ll see the list in the view. Pull to refresh several times, and you’ll see the order change! Remember, the repository shuffles the order of items returned.
When creating your view, you could use any implementation of MediaRepository you want. For example, you could create a repository that retrieves the items from a database or an API. The code for the view wouldn’t have to change, because all the calls go through the protocol.