解码JSON数组或字典错误swift

时间:2018-05-04 21:26:48

标签: json swift decode

这是我第一次在Codable / Decodable上拍摄,我想解码一个JSON。我试图访问"名称"和"描述"事件数组中的键。下面是JSON的片段 - 我在我的代码中收到此错误

"预计会解码字典,但会找到一个数组。"

"pagination": {

    "page_number": 1, 
    "page_size": 50, 
    "continuation": "eyJwYWdlIjogMn0", 
    "has_more_items": true
}, 

"events": [
    {
        "name": {
            "text": "Genesis Part 4", 
            "html": "Genesis Part 4"
        }, 

        "description": {
            "text": "Wednesday, June 6-June 27, 2018\n12:00-2:15 PM, Eastern Time\n\u00a0\nCOED\n\u00a0\nBible Study Leader:\u00a0Nicki Cornett\n\u00a0\nContact:NickiCornett@gmail.com\n\u00a0\nGenesis Part 4 -\u00a0Wrestling with God - A Study on Isaac, Jacob, and Esau- Precept Workbook (NASB)\n\u00a0\nGod renews His covenant promise with Abraham through Isaac and Jacob.

以下是我如何进行解码 - (注意 - "说明"还没有到来,因为我在使用事件数组进行名称和解释时遇到了问题

struct Eventbrite: Decodable {

 private enum CodingKeys : String, CodingKey { case events = "events",  name = "name"}
    let events: [String:[String]]
    let name: [String:[String]]

}

   URLSession.shared.dataTask(with: url) { (data, response, error) in

        guard let data = data else {return}

        do {

        let eventbriteData = try JSONDecoder().decode(Eventbrite.self, from: data)


            print(eventbriteData.name)

2 个答案:

答案 0 :(得分:2)

name显然不在paginationevents的范围内(请注意{}),并且是一个可以解码为[String:String]的常规description词典另一个结构。

对此进行解码(由于CodingKeys不完整我将其删除了),您不需要struct Eventbrite: Decodable { let events: [Event] } struct Event: Decodable { let name: Name // let description: [String:String] } struct Name : Decodable { let text, html : String }

private void promptFilmRating() {

    Scanner filmScanner = new Scanner(System.in);
    int filmRatingOutOfFive;

    do{
        System.out.println("Please enter your rating for the film:");
        filmRatingOutOfFive = filmScanner.nextInt();

        if(filmRatingOutOfFive > 5 || filmRatingOutOfFive < 1)
            System.out.println("Your number is outside of the rating boundaries, enter a number between 1 and 5.");

    }while(filmRatingOutOfFive > 5 || filmRatingOutOfFive < 1);


    System.out.println("You rated this film: "+filmRatingOutOfFive+" out of 5");


}

答案 1 :(得分:2)

对,所以Decodable实际上非常聪明,因为你真的不需要编写任何代码来自己进行解码。您只需确保匹配JSON结构(并为任何嵌套对象创建也符合Decodable的结构)。换句话说,不要将变量作为字典,而是将它们作为自己的Decodable结构。

例如:

struct EventBrite: Decodable {
    let pagination: Pagination
    let events: [Event]
}

struct Pagination: Decodable {
    let page_number: Int
    let page_size: Int
    let continuation: String
    let has_more_items: Bool
}

struct Event: Decodable { 
     let name: EventName
     let description: EventDescription
}

struct EventName: Decodable {
    let name: String
    let html: String
}

等...

其他重要的事情是,如果无法保证返回密钥或财产(例如,让我们说EventName并不总是有一个html值从服务器返回,您可以轻松地将该值标记为可选。所以类似于:

struct EventName: Decodable {
    let name: String
    let html: String?
}

另一方面,您实际上搞砸了您的字典类型声明。您会注意到event实际上是[String: [String: String]]类型,因为键是一个字符串,值似乎总是字典。名字是[String: String]。这不是你原来问题中的原因。

如果值与分页不同,您可能会执行[String: Any]之类的操作,所以请小心。

HOWEVER 我认为我认为的方法比将属性设为字典更好。对于一个你不必担心声明它的字典类型(你做了一些小错误)。但更重要的是,当每个词典成为自己明确定义的结构时,您不必担心记住或查找键。点语法/自动完成会自动告诉你可以有什么! (当您的值为AnyAnyObject类型时,不会进行转换!)

同样明确地使用所有这些结构,因为我曾经对性能和测量结构效率进行基准测试,其效率比类别高出数百万倍。只是一个FYI。