首页 > 解决方案 > 如何在 SwiftUI 中访问嵌套的 JSON API 数据?

问题描述

我正在尝试在 SwiftUI 中构建一个公共交通应用程序。我收到了一个 API,我可以在其中搜索瑞典斯德哥尔摩的始发站和目的地站,以及我想旅行的日期和时间,然后获取旅行路线。

这是我正在使用的 JSON 文件的一部分(完整的文件在下面的评论中):

{
  "Trip": [
    {
      "ServiceDays": [
        {
          "planningPeriodBegin": "2021-01-05",
          "planningPeriodEnd": "2021-05-20",
          "sDaysR": "m\u00e5n - fre",
          "sDaysI": "utom 13., 14. maj",
          "sDaysB": "33E7CF9F3E7CF9F3E7CF9C1E7CF9F3E70F"
        }
      ],
      "LegList": {
        "Leg": [
          {
            "Origin": {
              "name": "Skansen",
              "type": "ST",
              "id": "A=1@O=Skansen@X=18101848@Y=59323673@U=74@L=400110217@",
              "extId": "400110217",
              "lon": 18.101848,
              "lat": 59.323673,
              "prognosisType": "PROGNOSED",
              "time": "15:58:00",
              "date": "2021-04-06",
              "rtTime": "15:59:00",
              "rtDate": "2021-04-06",
              "hasMainMast": true,
              "mainMastId": "A=1@O=Skansen (Stockholm)@X=18100895@Y=59323960@U=74@L=300101405@",
              "mainMastExtId": "300101405",
              "additional": false
            },
            "Destination": {
              "name": "Manilla",
              "type": "ST",
              "id": "A=1@O=Manilla@X=18133759@Y=59323250@U=74@L=400110141@",
              "extId": "400110141",
              "lon": 18.133759,
              "lat": 59.32325,
              "prognosisType": "PROGNOSED",
              "time": "16:05:00",
              "date": "2021-04-06",
              "rtTime": "16:06:00",
              "rtDate": "2021-04-06",
              "hasMainMast": true,
              "mainMastId": "A=1@O=Manilla (Stockholm)@X=18134407@Y=59324185@U=74@L=300101426@",
              "mainMastExtId": "300101426",
              "additional": false
            },

这甚至不是完整 JSON 文件的四分之一,但我认为在这里添加它会太多,如果您想查看整个 JSON 文件,请发表评论

现在,我不专注于更改日期或时间,我只需要一种访问以下数据的方法:

- planningPeriodBegin
- planningPeriodEnd
- The "Origin" "name" (Skansen)
- The "Destination" "name" (Manilla)

我在 YouTube 上复制了一个教程,其中部分介绍了如何访问 JSON 文件 - 但不完全。这是视频的链接: https ://www.youtube.com/watch?v=-gNOVDNWmIg&list=LL&index=1&t=966s

...这是他在视频中写的代码:

import SwiftUI

struct RouteList: View {
    @State var gifUrl = String()
    @State var searchString = String()
    
    var body: some View {
        Text("\(gifUrl)")
            .onTapGesture {
                let url = URL(string: gifUrl)
                guard let GIPHYUrl = url, UIApplication.shared.canOpenURL(GIPHYUrl) else {return}
                UIApplication.shared.open(GIPHYUrl)
            }
        TextField("Search GIFs", text: $searchString)
            .multilineTextAlignment(.center)
        Button("Fetch Gif"){fetchAPI()}
    }

    func fetchAPI() {
        let apiKey = "xkkakigCSAnCN4Opymed36OoyByZEbBO"
        let url = URL(string: "https://api.giphy.com/v1/gifs/search?api_key=\(apiKey)&q=\(self.searchString)&limit=25&offset=0&rating=g&lang=en")
        URLSession.shared.dataTask(with: url!) { data, response, error in
            if let data = data {
                if let decodedGiphy = try? JSONDecoder().decode(GIPHYStructure.self, from: data){
                    self.gifUrl = decodedGiphy.data[0].url
                }
            }
        }.resume()
    }
    
}

struct GIPHYStructure: Decodable {
    let data: [dataStructure]
}

struct dataStructure: Decodable {
    let url: String
}

感谢您花时间阅读整篇文章,如果您能设法弄清楚如何去做,那将有很大帮助。我有一个指向 JSON 文件的 URL,但该密钥是私有的。

标签: jsonswiftapiswiftui

解决方案


您的 ...Structure 结构需要对您正在解码的 JSON 文件的结构进行建模。所以你会使用这样的东西(未经测试,因为你没有分享 URL):

struct APIStructure: Decodable {
    var Trip: [TripStructure]
}

struct TripStructure: Decodable {
    var ServiceDays: [ServiceDayStructure]
    var LegList: LegListStructure
}

struct ServiceDayStructure: Decodable {
    var planningPeriodBegin: Date
    var planningPeriodEnd: Date
}

struct LegListStructure: Decodable {
    var Leg: [LegStructure]
}

struct LegStructure: Decodable {
    var Origin: StationStructure
    var Destination: StationStructure
}

struct StationStructure: Decodable {
    var name: String
}

然后你可以大致像这样获取和解码 JSON:

func fetchAPI() {
    
    let url = URL(string: "https://api.giphy.com/v1/gifs/search?api_key=\(apiKey)&q=\(self.searchString)&limit=25&offset=0&rating=g&lang=en")
    URLSession.shared.dataTask(with: url!) { data, response, error in
        if let data = data {
            let decoder = JSONDecoder()
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd"
            decoder.dateDecodingStrategy = .formatted(formatter)
            if let decodedJSON = try? decoder.decode(APIStructure.self, from: data){
                // Examples how to access the decoded values:
                let firstTripFirstPlanningPeriodBegin: Date = decodedJSON.Trip[0].ServiceDays[0].planningPeriodBegin
                let firstTripFirstLegOrigin: String = decodedJSON.Trip[0].LegList.Leg[0].Origin.name
            }
        }
    }.resume()
}

这一切都在本文中更详细地解释:https ://learnappmaking.com/codable-json-swift-how-to/


推荐阅读