I have a basic view that displays a list that fetches data from an API. I want to implement an activity indicator while the data is being retrieved from the API. In MVC we could use a delegate and protocol and make the view controller inherit the protocol, and after the model has finished fetching the data we call the delegate to tell the view controller that the data has finished retrieving (now hide the activity indicator, etc.). How to achieve a similar thing in SwiftUI and it's MVVM style?
I have tried implementing an activity indicator from this question, I just don't get how and when to stop it: Activity indicator in SwiftUI
My SourcesViewModel (it fetches news article sources from newsapi.org)
import UIKit
class SourcesViewModel: Identifiable {
let id = UUID()
let source: Sources
init(source: Sources) {
self.source = source
}
var name: String {
return self.source.sourceName
}
var description: String {
return self.source.sourceDescription
}
}
My SourcesListViewModel:
import Combine
class SourcesListViewModel: ObservableObject {
init() {
fetchSources()
}
@Published var sources = [SourcesViewModel]()
private func fetchSources() {
NetworkManager.shared.getSourceData { (sources) in
self.sources = sources.map(SourcesViewModel.init)
}
}
}
Lastly, my SourcesView:
import SwiftUI
struct SourcesView: View {
@ObservedObject var model = SourcesListViewModel()
var body: some View {
ActivityIndicatorView(isShowing: .constant(true)) {
NavigationView {
List(self.model.sources) { source in
VStack(alignment: .center) {
Text(source.name)
Text(source.description)
.foregroundColor(.secondary)
.lineLimit(3)
}
.navigationBarTitle(Text("Sources"), displayMode: .inline)
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
SourcesView()
}
}
The result:
Your view model should have loading state, like the following
@Published var loading = false
private func fetchSources() {
self.loading = true
NetworkManager.shared.getSourceData { (sources) in
self.sources = sources.map(SourcesViewModel.init)
self.loading = false
}
}
and activity indicator should be bound to it, like
ActivityIndicatorView(isShowing: $model.loading) {
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With