如何在SwiftUI中解码嵌套的JSON?

68de4m5k  于 2023-05-16  发布在  Swift
关注(0)|答案(1)|浏览(208)

问题

我使用Google的自定义搜索API创建了一个自定义搜索引擎,并希望在我的swiftUI应用程序中显示选定的结果。
完整的JSON可以在here.中找到
我想检索要显示的每个“项目”示例的“标题”和“链接”。
为清晰起见,编辑了示例JSON:

{
  "kind": "customsearch#search",
  "url": { ...
  },
  "queries": { ...
  },
  "context": {
    "title": "Running News"
  },
  "searchInformation": {
    "searchTime": 0.356204,
    "formattedSearchTime": "0.36",
    "totalResults": "2930",
    "formattedTotalResults": "2,930"
  },
  "items": [
    {
      "kind": "customsearch#result",
      "title": "DyeStat.com - Issam Asinga Runs 9.83w 100m, Beats Noah Lyles",
      "link": "https://www.dyestat.com/gprofile.php?mgroup_id=44531&do=news&news_id=660245",
      ...
    },

代码至今

import SwiftUI

struct Response: Codable { // queries
    let items: [Items]
    
    struct Items: Codable {
        let title: String
        let link: String
    }
}

struct NewsView: View {
    @State private var responseItems = [Response.Items]()
    
    var body: some View {
        NavigationStack {
            List(responseItems, id: \.link) { item in
                VStack(alignment: .leading) {
                    Text(item.link)
                }
            }
            .task {
                await loadData()
            }
        }
    }
    
    func loadData() async {
        let url: String = "https://www.googleapis.com/customsearch/v1?"
        let apiKey: String = "AIzaSyBYICPHm9JtYCK_y5LtCxaZ23w_-EMECYU"
        let searchEngineId: String = "156370c9cc30c4c53"
        let query: String = "Lyles"
        
        guard let url = URL(string: "\(url)key=\(apiKey))&cx=\(searchEngineId)&q=\(query)&num(5)") else {
            print("Invalid URL")
            return
        }
        
        do {
            let (data, _) = try await URLSession.shared.data(from: url)

            do {
                let decodedResponse = try JSONDecoder().decode(Response.self, from: data)
                responseItems = decodedResponse.items
            } catch {
                print(error)
            }
        } catch {
            print("Invalid data")
        }
    }
}

结果

当我在Xcode中运行时,我得到以下错误:
keyNotFound(CodingKeys(stringValue:“items”,intValue:nil),Swift.DecodingError.Context(codingPath:[],debugDescription:“没有与键CodingKeys(stringValue:“items”,intValue:nil)(“items”).",underlyingError:(无))
“items”匹配JSON中的文本,所以我不确定为什么需要codingKeys。
任何帮助将不胜感激!

zbwhf8kr

zbwhf8kr1#

首先请将Items命名为单数形式Item一个示例代表一个项。
这是一个很好的例子,为什么强烈建议使用字符串插值来组成URL。

apiKey后面有两个右括号,第二个右括号是错误的,因为它是API key的一部分。

一个更可靠的(也是推荐的)方法是URLComponentsURLQueryItem,特别是对于许多查询键/值对。
这个版本的loadData抛出所有可以在调用方处理的错误

func loadData() async throws {
    let baseURL = "https://www.googleapis.com/customsearch/v1?"
    let apiKey = "AIzaSyBYICPHm9JtYCK_y5LtCxaZ23w_-EMECYU"
    let searchEngineId = "156370c9cc30c4c53"
    let query = "Lyles"
    
    var urlComponents = URLComponents(string: baseURL)!
    urlComponents.queryItems = [
        URLQueryItem(name: "key", value: apiKey),
        URLQueryItem(name: "cx", value: searchEngineId),
        URLQueryItem(name: "q", value: query),
        URLQueryItem(name: "num", value: "5")
    ]
    
    guard let url = urlComponents.url else { throw URLError(.badURL) }
    let (data, _) = try await URLSession.shared.data(from: url)
    let decodedResponse = try JSONDecoder().decode(Response.self, from: data)
    responseItems = decodedResponse.items
}

并捕获错误更好地向用户显示适当的错误消息

.task {
    do {
        try await loadData() 
    } catch {
        print(error)
    }    
}

相关问题