【问题标题】:SwiftUI with JSON ObservedObject带有 JSON ObservedObject 的 SwiftUI
【发布时间】:2020-08-01 11:31:30
【问题描述】:

我目前正在学习 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()
    }
}

谁能帮忙指出我哪里出错了?

【问题讨论】:

    标签: json xcode parsing swiftui observedobject


    【解决方案1】:

    问题与异步 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)
                }
        }
    }
    }
    

    【讨论】:

      【解决方案2】:

      您尝试访问.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
                  }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-15
        • 2020-12-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多