Group Group Group Group Group Group Group Group Group

How to fetch data from API in SwiftUI views?

I’ve done a little iOS development in Swift, and loving SwiftUI, but I’m struggling to understand how and where to fetch data from external web services (APIs) in my SwiftUI views?

I have a simple list view that looks like this:

import SwiftUI

struct VideoListView: View {
    var videos = [Video]()

    var body: some View {
        NavigationView {
            List {
                ForEach(videos) { video in
                    VideoListItem(video)
                }
            }
            .navigationBarTitle(Text("Videos"))
        }
    }
}

But I’m unsure how to populate the videos property.

I’ve seen tutorials that use the new Combine framework and whilst I get the concept of pub/sub, I’m struggling to understand how to implement this practically, as tutorials seem to cover a single API endpoint. I have an API with multiple endpoints, so what am I supposed to do for those? Create multiple classes with practically the same source code to send a request to a URL and decode its contents?

My thinking was that I could have a single class that has the responsibility of sending a request and fetching the response data; and another class that then decodes the response data into instances of the models I’m expecting, but not sure how to get started with this. Do this sound the right way to go?

If any one knows of any tutorials that show how to fetch data from APIs in a reusable way in a SwiftUI project, or has pointers for me, that’d be most helpful!

Hi,
Before I suggest what can be done, I advice you to read Combine book by Ray Wenderlich, there you will get the concept. Chapter 8 has Networking session as well.

Let’s say you have a view model, you will do your endpoint call there. That view model will conform ObservableObject so that your View can subscribe to any changes. When you fetch your data, you will set it to your property like users: [User] in your code it is videos. Please see the below.

class VideoViewModel: ObservableObject {
    @Published var videos = [Video]()

    func fetchVideos() {
        // your endpoint call here
        // Once finished set to your videos
        // videos = endpoint.videos
    }
}

View

struct VideoListView: View {

    @ObservedObject private var viewModel = VideoViewModel()

    var body: some View {
        NavigationView {
            List {
                ForEach(viewModel.videos) { video in
                    VideoListItem(video)
                }
            }
            .navigationBarTitle(Text("Videos"))
        }
    }
}

Hope it helps

Thanks! So in your example, you have a separate class for the view model that I ask for videos, rather than trying to get videos into the SwiftUI view itself.

In your example, the view model has a fetchVideos method that does the actual network call and populates the videos property. How is that method invoked from my SwiftUI view?

You can fetch immediately when you initialise view model’s init, you can trigger via button in your view. or like there is onAppear {} you can use in your view.

struct VideoListView: View {

    @ObservedObject private var viewModel = VideoViewModel()

    var body: some View {
        VStack {
            Button(action: {
                self.viewModel.fetchVideos()
            }) {
                Text("Fetch Videos")
            }
        }.onAppear {
            self.viewModel.fetchVideos()
        }
    }
}

Hope it helps.

Brilliant. Thank you for your help! I’ll start experimenting, and take a look at the Combine reference you pointed me to.

Thanks again!