繁体   English   中英

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

[英]Create Object from JSON Object in Swift 5

需要从 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]] 的数组 let jsonData = try JSONSerialization.data(withJSONObject: jsonResponse["data"] as! [[String:Any]])

您只是缺少 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(fromdecoder: 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. 旧方法 - 从您的 JSON 创建 init
  2. 将 JSON 转换为数据。 在我的情况下,该选项有帮助
let data = try JSONSerialization.data(withJSONObject: dictionary, options: [.fragmentsAllowed])

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

型号分类:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM