【问题标题】:Create Object from JSON Object in Swift 5在 Swift 5 中从 JSON 对象创建对象
【发布时间】:2019-10-28 16:41:14
【问题描述】:

需要从 JSON 对象创建对象

来自 API 的 JSON 响应

{
    "id": 1,
    "name": "Cricket",
    "slug": "cricket",
    "banner_image": "https://cricket.jpg",
    "icons": {
        "green": "http://localhost:8000/sport_icon_cricket_green.png",
        "grey": "http://localhost:8000/sport_icon_cricket_gray.png",
        "white": "http://localhost:8000/sport_icon_cricket_white.png",
        "black": "http://localhost:8000/sport_icon_cricket_black.png"
    }
},
{
    "id": 2,
    "name": "Baseball",
    "slug": "baseball",
    "banner_image": "https://baseball.jpg",
    "icons": {
        "green": "http://localhost:8000/sport_icon_baseball_green.png",
        "grey": "http://localhost:8000/sport_icon_baseball_gray.png",
        "white": "http://localhost:8000/sport_icon_baseball_white.png",
        "black": "http://localhost:8000/sport_icon_baseball_black.png"
    }
},

我创建了struct,如下所示

以下链接错误struct ObjSportsList:Codable

struct ObjSportsList:Codable { // Error on this line -> Error : Type 'ObjSportsList' does not conform to protocol 'Decodable'

    var id:Int
    var name:String
    var slug:String
    var icons:ObjSportsIcon
}

struct ObjSportsIcon {
    var green:String
    var grey:String
    var white:String
    var black:String
}

像这样解码

let decoderdec = JSONDecoder()
                        decoderdec.keyDecodingStrategy = .convertFromSnakeCase
                        // 2. Create Data from Response
                        let jsonData = try JSONSerialization.data(withJSONObject: jsonResponse["data"] as! [[String:Any]])

                        // 3 Convert Data to Object (Array) if don't user array then only pass ObjCountry.self
                        self.arrSports.removeAll()
                        self.arrSports = try decoderdec.decode([ObjSportsList].self, from: jsonData)

解码行出错:无法分配“[ObjSportsList]”类型的值 输入 '[[String : Any]]'

更新

// 错误 2.Create Data from Response // 这是 [[String:Any]] 的数组 let jsonData = try JSONSerialization.data(withJSONObject: jsonResponse["data"] as! [[String:Any]])

【问题讨论】:

  • 你也应该让“ObjSportsIcon”结构符合 Codable 协议
  • ObjSportsIcon 应确认为Codable
  • 你能举个例子吗?
  • 您的错误说明了一切,您的 json 响应是字典,而您正在查看数组。将您的响应更改为从数组开始

标签: ios json swift


【解决方案1】:

您只是缺少使用 ObjSportsIcon 类的 Codable 实现。

struct ObjSportsList : Codable {
    
    var id:Int
    var name:String
    var slug:String
    var icons:ObjSportsIcon
}

struct ObjSportsIcon : Codable {
    var green:String
    var grey:String
    var white:String
    var black:String
}

或者您可以使用以下代码使其正确:

public struct ObjSportsList : Codable {
    
    var id:Int
    var name:String
    var slug:String
    var icons:ObjSportsIcon
    
    public init(id: Int, name: String, slug: String, icons: ObjSportsIcon) {
        self.id = id
        self.name = name
        self.slug = slug
        self.icons = icons
    }
    
    public enum CodingKeys: String, CodingKey {
        case id
        case name
        case slug
        case icons
    }
}

public struct ObjSportsIcon : Codable {
    var green:String
    var grey:String
    var white:String
    var black:String
    
    public init(green: String, grey: String, white: String, black: String) {
        self.green = green
        self.grey = grey
        self.white = white
        self.black = black
    }
    
    public enum CodingKeys: String, CodingKey {
        case green
        case grey
        case white
        case black
    }
}

更改以下代码行以解决您的第二个错误:

self.arrSports = try decoderdec.decode(Array<ObjSportsList>.self, from: jsonData)

Vivek 更新:

我找到了我的错误和第二个错误的解决方案

旧代码 var arrSports:[[String:Any]] = []

新代码 var arrSports:[ObjSportsList] = []


你必须实现 init(from decoder: Decoder) 方法来达到同样的效果。 注意:您必须为每个属性设置默认值

struct ObjSportsIcon : Codable {
    var green:String
    var grey:String
    var white:String
    var black:String
    var pink:String
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.green = try container.decodeIfPresent(String.self, forKey: .green) ?? "green"
        self.grey = try container.decodeIfPresent(String.self, forKey: .grey) ?? "grey"
        self.white = try container.decodeIfPresent(String.self, forKey: .white) ?? "white"
        self.black = try container.decodeIfPresent(String.self, forKey: .black) ?? "black"
        self.pink = try container.decodeIfPresent(String.self, forKey: .pink) ?? "pink"
    }
}

【讨论】:

  • 感谢您的回答,第一个错误已解决,如声明结构,但在self.arrSports = try decoderdec.decode([ObjSportsList].self, from: jsonData) 上仍然出现错误错误:无法将类型“[ObjSportsList]”的值分配给类型“[[String : Any]]”
  • @Vivek 检查更新的答案,您只需要更改一行代码。
  • @Vivek 你之前没有提到过 arrSport 的声明 :),反正它解决了很好。
  • icons:ObjSportsIcon 中的“粉红色”等可选键的任何方式?
  • icons:ObjSportsIcon 中的“粉红色”等可选密钥的任何方式?,我想添加我自己的密钥,如 selected:Bool,这不是从 API 接收的,我将更改 selected 密钥通过选择 tableview 并在 tableview 单元格上显示 selected 键。
【解决方案2】:

嗯,有两种选择:

  1. 旧方法 - 从 JSON 创建初始化
  2. 将 JSON 转换为数据。就我而言,该选项有帮助
let data = try JSONSerialization.data(withJSONObject: dictionary, options: [.fragmentsAllowed])

【讨论】:

    【解决方案3】:

    我不知道为什么会遇到这个问题,因为我已经尝试复制粘贴您的代码。一切工作正常。请参考下面的代码。

    模型类:

    struct ObjSportsList : Decodable {
        var id:String
        var name:String
        var slug:String
        var icons:ObjSportsIcon
    }
    
    struct ObjSportsIcon : Decodable {
        var green:String
        var grey:String
        var white:String
        var black:String
    }
    

    解析代码:

    let decoderdec = JSONDecoder()
    decoderdec.keyDecodingStrategy = .convertFromSnakeCase
    
    let aryTemp = [[
            "id": "1",
            "name": "Cricket",
            "slug": "cricket",
            "banner_image": "https://cricket.jpg",
            "icons": [
                "green": "http://localhost:8000/sport_icon_cricket_green.png",
                "grey": "http://localhost:8000/sport_icon_cricket_gray.png",
                "white": "http://localhost:8000/sport_icon_cricket_white.png",
                "black": "http://localhost:8000/sport_icon_cricket_black.png"
        ]],[
            "id": "2",
            "name": "Baseball",
            "slug": "baseball",
            "banner_image": "https://baseball.jpg",
            "icons": [
                "green": "http://localhost:8000/sport_icon_baseball_green.png",
                "grey": "http://localhost:8000/sport_icon_baseball_gray.png",
                "white": "http://localhost:8000/sport_icon_baseball_white.png",
                "black": "http://localhost:8000/sport_icon_baseball_black.png"
            ]
        ]]
    
    do {
        let jsonData = try JSONSerialization.data(withJSONObject: aryTemp)
        let arrSports = try decoderdec.decode([ObjSportsList].self, from: jsonData)        
        print(arrSports)
    } catch let error {
        print(error)
    }
    

    【讨论】:

    • OP 提供的 json 与您在代码中提到的内容存在很大差异。所以你怎么能说你只是复制粘贴了他的代码,一切正常
    • @Vikky 我刚刚将 JSON 数组转换为 Swift 数组语法。
    • 但是 OP 的 json 响应不是一个数组。看看他提到了什么错误
    • @Vikky 再次阅读问题。另外,如果你全神贯注于代码,那么你已经注意到,OP 被问及 Array。
    • 是的,他在更新中提到了这一点,但是他发布的 json 是无效的 json。但是如果我们假设它的数组那么一切正常
    猜你喜欢
    • 2020-05-08
    • 2015-03-27
    • 1970-01-01
    • 2020-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    • 1970-01-01
    相关资源
    最近更新 更多