SwiftUI с JSON ObservedObject
В настоящее время я изучаю SwiftUI, и у меня проблемы с получением кода для печати вызова из API
NetworkManager.swift
class NetworkManager: ObservableObject {
@Published var allCountries = Countries()
func fetchAllCountries() {
if let url = URL(string: K.url) {
print(url)
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
if error == nil {
let decoder = JSONDecoder()
if let countriesData = data {
do {
let countries = try decoder.decode(Countries.self, from: countriesData)
DispatchQueue.main.async {
self.allCountries = countries
}
} catch {
print(error)
}
}
}
}
task.resume()
}
}
}
Если я напечатаю все страны, я смогу увидеть каждый элемент
Но в моем главном представлении при попытке печати (self.networkManager[5].name) я получаю ошибку индекса вне допустимого диапазона.
ContentView.swift
import SwiftUI
struct ContentView: View {
@ObservedObject var networkManager = NetworkManager()
var body: some View {
Text("Hello, World!")
.onAppear {
self.networkManager.fetchAllCountries()
print(self.networkManager.allCountries[5].name)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Может ли кто-нибудь помочь указать, где я ошибаюсь?
2 ответа
Проблема связана с асинхронным fetchAllCountries. Вам нужно дождаться его завершения, прежде чем пытаться использовать результаты. Попробуйте что-нибудь вроде этого;
class NetworkManager: ObservableObject {
@Published var allCountries = Countries()
func fetchAllCountries(handler: @escaping () -> Void) {
if let url = URL(string: K.url) {
print(url)
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
if error == nil {
let decoder = JSONDecoder()
if let countriesData = data {
do {
let countries = try decoder.decode(Countries.self, from: countriesData)
DispatchQueue.main.async {
self.allCountries = countries
return handler()
}
} catch {
print(error)
}
}
}
handler()
}
task.resume()
}
}
}
struct ContentView: View {
@ObservedObject var networkManager = NetworkManager()
var body: some View {
Text("Hello, World!")
.onAppear {
self.networkManager.fetchAllCountries() {
print(self.networkManager.allCountries[5].name)
}
}
}
}
Вы пытаетесь получить доступ .allCountries
слишком рано, потому что .fetchAllCountries
это долгая (относительно) асинхронная операция.
Решение состоит в том, чтобы добавить явного наблюдателя в выбранные страны, как показано ниже.
var body: some View {
Text("Hello, World!")
.onAppear {
self.networkManager.fetchAllCountries()
}
.onReceive(networkManager.$allCountries) { countries in
print(countries[5].name) // assuming Countries support subscript
}
}