簡體   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