Hi,
I am experimenting with SwiftUI and Combine after watching https://developer.apple.com/videos/play/wwdc2019/226/ ( Data Flow Through SwiftUI ).
So I created a Publisher to load some data via network call, something like this:
var countriesPublisher: AnyPublisher<[Country], Never> = {
let urlSession = URLSession.shared
let url = URL(string: "https://www.ralfebert.de/examples/countries.json")!
return urlSession
.dataTaskPublisher(for: url)
.map { $0.data }
.decode(type: [Country].self, decoder: JSONDecoder())
.assertNoFailure() // todo: no error handling right now
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
}()
And I want to use this in a SwiftUI view. Now the WWDC talk recommended to use @State to hold the data, subscribe to it via onReceive and copy it to the internal state. This works, f.e.:
struct CountriesListView: View {
@State var countries = [Country]()
var body: some View {
List(countries) { country in
Text(country.name)
}
.onReceive(countriesPublisher) { countries in
self.countries = countries
}
}
}
(the example project is available here: https://github.com/ralfebert/Countries/archive/ed73ddb5423548d54375f62904d8e81f7f7841d2.zip )
Ok, this works and it's pretty cool already. But:
- I liked the 'single source of truth' principle mentioned in the talk, but this violates it by copying the state. I consider the output of the Publisher to be this source of truth.
- For the PreviewProvider I'd like to be able to pass in static data, and in that case, I don't want the onReceive to be called.
- It was recommended to keep @State private which made sense to me, but if I want to move the onReceive() call out / one level up, this cannot be private anymore.
Are there any best practices already how to connect a SwiftUI view to such a Publisher?
Greetings,
Ralf