【问题标题】:Getting JSON from a public API to render in a list view in SwiftUI从公共 API 获取 JSON 以在 SwiftUI 的列表视图中呈现
【发布时间】:2019-12-03 04:29:02
【问题描述】:

我正在尝试从Rest Api 获取数据以下载并在SwiftUI 的列表视图中呈现。 我想我设法让JSON 正确下载并分配给所有相关的结构,但是当我去构建它时,模拟器的列表视图中没有显示任何内容。

我什至不确定是否需要在其中添加“Enum CodingKeys”。

谁能指出我哪里出错了?

import Foundation
import SwiftUI
import Combine


struct ContentView: View {
    @ObservedObject var fetcher = LaunchDataFetcher()

    var body: some View {
        VStack {
            List(fetcher.launches) { launch in
                VStack (alignment: .leading) {
                    Text(launch.mission_name)
                    Text(launch.details)
                        .font(.system(size: 11))
                        .foregroundColor(Color.gray)
                }
            }
        }
    }
}

public class LaunchDataFetcher: ObservableObject {

    @Published var launches = [launch]()
    init(){
        load()
    }

    func load() {
        let url = URL(string: "https://api.spacexdata.com/v3/launches")!
        URLSession.shared.dataTask(with: url) {(data,response,error) in
            do {
                if let d = data {
                    let decodedLists = try JSONDecoder().decode([launch].self, from: d)
                    DispatchQueue.main.async {
                        self.launches = decodedLists
                    }
                }else {
                    print("No Data")
                }
            } catch {
                print ("Error")
            }

        }.resume()

    }
}

struct launch: Codable {
    public var flight_number: Int
    public var mission_name: String
    public var details: String

    enum CodingKeys: String, CodingKey {
           case flight_number = "flight_number"
           case mission_name = "mission_name"
           case details = "details"
        }
}

// Now conform to Identifiable
extension launch: Identifiable {
    var id: Int { return flight_number }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

【问题讨论】:

  • 如果键和结构成员具有相同的名称,则不需要 CodingKeys。如果您将结构成员命名为 camelCased 并添加 convertFromSnakeCase 键解码策略,您甚至不需要 CodingKeys。
  • 我以为是这样。感谢您的建议。

标签: ios swiftui xcode11 swift5.1 swiftui-list


【解决方案1】:

首先,我尝试找出您的代码的哪个错误,并识别某处响应数据的launch.details为空。所以我只是将此属性标记为可选并且它可以工作。

更多细节,你可以参考下面的代码:

struct launch: Codable {
    public var flight_number: Int
    public var mission_name: String
    public var details: String?

    enum CodingKeys: String, CodingKey {
           case flight_number = "flight_number"
           case mission_name = "mission_name"
           case details = "details"
        }
}

在捕获线,获取错误消息以准确了解发生了什么

func load() {
        let url = URL(string: "https://api.spacexdata.com/v3/launches")!
        URLSession.shared.dataTask(with: url) {(data,response,error) in
            do {
                if let d = data {
                    let decodedLists = try JSONDecoder().decode([launch].self, from: d)
                    DispatchQueue.main.async {
                        print(decodedLists)
                        self.launches = decodedLists
                    }
                }else {
                    print("No Data")
                }
            } catch let parsingError {
                print ("Error", parsingError)
            }

        }.resume()
    }

希望对您有所帮助!

【讨论】:

  • @Lofty 给我投票吧,这会让我更有动力^_^
【解决方案2】:

控制台中有任何消息吗?我认为您需要在 .plist 中添加 NSAppTransportSecurity>NSAllowsArbitraryLoads>YES

Transport security has blocked a cleartext HTTP

【讨论】:

  • 我不需要这样做。
【解决方案3】:

在 Trai Nguyen 的帮助下,我设法让模拟器显示数据。

我所缺少的只是确保名为“详细信息”的变量具有可选属性(通过添加“?”) - 就像这样:

 public var details: String?

然后确保当我在视图中呈现文本时,如果返回为空,我必须给它一个值以插入 - 就像这样:

Text(launch.details ?? "No Data Found")

这是适合我的完整代码:

import Foundation
import SwiftUI
import Combine


struct ContentView: View {
    @ObservedObject var fetcher = LaunchDataFetcher()

    var body: some View {
        VStack {
            List(fetcher.launches) { launch in
                VStack (alignment: .leading) {
                    Text(launch.mission_name)

                    Text(launch.details ?? "No Data Found")
                        .font(.system(size: 11))
                        .foregroundColor(Color.gray)
                }
            }
        }
    }
}


public class LaunchDataFetcher: ObservableObject {

    @Published var launches = [launch]()

    init(){
        load()
    }

    func load() {
        let url = URL(string: "https://api.spacexdata.com/v3/launches")!
        URLSession.shared.dataTask(with: url) {(data,response,error) in
            do {
                if let d = data {
                    let decodedLists = try JSONDecoder().decode([launch].self, from: d)
                    DispatchQueue.main.async {
                        print(decodedLists)
                        self.launches = decodedLists
                    }
                }else {
                    print("No Data")
                }
            } catch let parsingError {
                print ("Error", parsingError)
            }

        }.resume()
    }
}

struct launch: Codable {
    public var flight_number: Int
    public var mission_name: String
    public var details: String?
}

/// Now conform to Identifiable
extension launch: Identifiable {
    var id: Int { return flight_number }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-29
    • 2020-03-16
    • 2019-12-27
    • 2021-07-09
    • 2010-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多