在Swift 5中从JSON对象创建对象

时间:2019-06-14 04:40:46

标签: ios json swift

需要从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.从响应创建数据 //这是[[String:Any]]的数组                               让jsonData =尝试JSONSerialization.data(withJSONObject:jsonResponse [“ data”] as![[String:Any]])

3 个答案:

答案 0 :(得分:2)

您只是缺少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(来自解码器: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"
    }
}

答案 1 :(得分:1)

有两种选择:

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

答案 2 :(得分:0)

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

模型类:

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)
}