簡體   English   中英

Swift 4 JSON解碼器

[英]Swift 4 JSON Decoder

我知道其他問題已經解決了這個問題,但是我已經關注了這些問題,但仍然感到困惑。 這是我的JSON結構:

      {
       "FindBoatResult": {
       "num_boats": 10,
       "boat": [
         {
           "num_segments": 1,
           "segments": [
              {
               "ident": "String",
                "origin" : {
                         "code" : "String"
                 },
           },
         ]
        }

等等...但這就是結構的深度。 每個JSON響應中都有多個“段”返回。 在Swift中,我有這段代碼。

struct Result : Decodable {
    let FindBoatResult : FindBoatResult
}
struct FindBoatResult : Decodable {
    let boats : Boats
    let num_boats : Int
}
struct Boats : Decodable {
    let segments : [Segments]
}
struct Segments : Decodable {
    let ident : String?
    let origin : Origin
}
struct Origin : Decodable {
    let code : String
}

func getBoats() {

let urlString = "http://myApi"
guard let url = URL(string: urlString) else { return }

    URLSession.shared.dataTask(with: url) { (data, response, err) in
        guard let data = data else {return}
        let dataAsString = String(data: data, encoding: .utf8)
        //print(dataAsString)

        do {
            let boats = try
                JSONDecoder().decode(FindBoatResult.self, from: data)

            print(boats)
        } catch {
            print(err) 
        }  
    }.resume()
}

這會失敗並拋出err,但err會顯示為nil..so,所以我無法說出我所缺少的內容。 dataAsString按預期方式打印出JSON,因此我知道“數據”是好的。

我發現了幾個小問題。 嘗試替換此:

struct FindBoatResult: Decodable {
    let boats: Boats
    let num_boats: Int
}
struct Boats: Decodable {
    let segments: [Segments]
}

有:

struct FindBoatResult: Decodable {
    let boat: [Boat]
    let num_boats: Int
}
struct Boat: Decodable {
    let segments: [Segments]
}

最后,使用Result類型(而不是FindBoatResult )進行解碼:

JSONDecoder().decode(Result.self, from: data)

擴展Paulo的答案,我可能進一步建議,如果您堅持使用的鍵具有與屬性名稱不符合Swift約定的鍵,則可以使用CodingKeys模式將JSON鍵轉換為更好的Swift屬性名稱,例如:

struct BoatResult: Decodable {           // I'd simplify this name
    let boatCollection: BoatCollection

    enum CodingKeys: String, CodingKey {
        case boatCollection = "FindBoatResult"
    }
}

struct BoatCollection: Decodable {       // I'd simplify this, too, removing "Find" from the name; verbs are for methods, not properties 
    let boats: [Boat]
    let numberOfBoats: Int

    enum CodingKeys: String, CodingKey {
        case boats = "boat"              // "boat" isn't great property name for an array of boats, so let's map the poor JSON key to better Swift name here
        case numberOfBoats = "num_boats" // likewise, let's map the "_" name with better camelCase property name
    }
}

struct Boat: Decodable {                 // This entity represents a single boat, so let's use "Boat", not "Boats"
    let segments: [Segment]
}

struct Segment: Decodable {              // This entity represents a single segment, so let's use "Segment", not "Segments"
    let identifier: String
    let origin: Origin

    enum CodingKeys: String, CodingKey {
        case identifier = "ident"        // `ident` isn't a common name for identifier, so let's use something more logical
        case origin
    }
}

struct Origin: Decodable {
    let code: String
}

因此,例如,使用多個(如boats ),當你代表對象的數組,並使用CodingKeys的誤導映射boat JSON關鍵,這更好的命名boats數組引用。 或者,當您擁有num_boats類的鍵時,您不必感覺自己必須在Swift屬性中使用該壞名,而不必使用諸如numberOfBoats (或count或其他任何東西)之類的更好的名稱,而不必使用_語法,這是非常不明智的。

顯然,如果您控制着JSON的設計,則可以在那里修復一些選擇不佳的鍵名,但是即使您決定要Web服務使用_語法,也可以繼續使用CodingKeys確保您的Swift對象遵守camelCase約定。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM