【问题标题】:How to decode a named array of json objects in Swift如何在 Swift 中解码一个命名的 json 对象数组
【发布时间】:2018-06-08 06:43:17
【问题描述】:

我有一个通过 API 调用接收到的 json 对象的命名数组。

{
    "Images": [{
        "Width": 800,
        "Height": 590,
        "Url": "https://obfuscated.image.url/image1.jpg"
        }, {
        "Width": 800,
        "Height": 533,
        "Url": "https://obfuscated.image.url/image2.jpg"
        }, {
        "Width": 800,
        "Height": 478,
        "Url": "https://obfuscated.image.url/image3.jpg"
    }]
}

对象是 Image 类型,我已经定义了它并且有一个可以解码单个 Image 对象的解码函数。图片如下:

struct Image : Codable {
    let width: CGFloat
    let height: CGFloat
    let url: String

    enum ImageKey: String, CodingKey {
        case width = "Width"
        case height = "Height"
        case url = "Url"
    }

    init(from decoder: Decoder) throws
    {
        let container = try decoder.container(keyedBy: ImageKey.self)
        width = try container.decodeIfPresent(CGFloat.self, forKey: .width) ?? 0.0
        height = try container.decodeIfPresent(CGFloat.self, forKey: .height) ?? 0.0
        url = try container.decodeIfPresent(String.self, forKey: .url) ?? ""
    }

    func encode(to encoder: Encoder) throws
    {
    }
}

我已经为这个场景写了一个测试,但这就是我难住的地方!测试失败(自然),看起来像这样:

func testManyImages() throws {

    if let urlManyImages = urlManyImages {
        self.data = try? Data(contentsOf: urlManyImages)
    }

    let jsonDecoder = JSONDecoder()
    if let data = self.data {
        if let _images:[Image] = try? jsonDecoder.decode([Image].self, from: data) {
            self.images = _images
        }
    }

    XCTAssertNotNil(self.images)
}

我的问题是这样的:

如何通过名称“Images”或其他方式访问图像数组?

感谢您的阅读,一如既往地感谢您的帮助。

【问题讨论】:

    标签: json swift jsondecoder


    【解决方案1】:

    我认为您的 Codable 结构是错误的。应该是:

    struct JSONStructure: Codable {
        let images: [Images]
        private enum CodingKeys: String, CodingKey {
            case images = "Images"
        }
    }
    
    struct Images: Codable {
        let width: CGFloat
        let height: CGFloat
        let url: String
    
        private enum CodingKeys: String, CodingKey {
            case width  = "Width"
            case height = "Height"
            case url    = "Url"
        }
    
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            width         = try container.decodeIfPresent(CGFloat.self, forKey: .width) ?? 0.0
            height        = try container.decodeIfPresent(CGFloat.self, forKey: .height) ?? 0.0
            url           = try container.decodeIfPresent(String.self, forKey: .url) ?? ""
        }
    
        func encode(to encoder: Encoder) throws {
        }
    }
    

    然后:

    if let data = self.data {
       if let decoded = try? jsonDecoder.decode(JSONStructure.self, from: data) {
           print("Decoded : \(decoded)")
           self.images = decoded.images
       }
    }
    

    日志:

    解码:JSONStructure(图像:[DreamSiteradio.Images(宽度:800.0, 高度:590.0,网址:“https://obfuscated.image.url/image1.jpg”), DreamSiteradio.Images(宽度:800.0,高度:533.0,网址: "https://obfuscated.image.url/image2.jpg"), DreamSiteradio.Images(宽度:800.0,高度:478.0,网址: "https://obfuscated.image.url/image3.jpg")])

    【讨论】:

    • 谢谢@Sharad Chauhan
    【解决方案2】:

    您可以创建 2 个结构而不是 1 个来解析完整的响应,即

    struct Response: Codable
    {
        let images: [Image]?
        enum CodingKeys: String, CodingKey
        {
            case images = "Images"
        }
    }
    struct Image : Codable
    {
        var width: CGFloat?
        let height: CGFloat?
        let url: String?
    
        enum CodingKeys: String, CodingKey
        {
            case width = "Width"
            case height = "Height"
            case url = "Url"
        }
    }
    

    由于响应中有嵌套级别,这就是我创建多个结构的原因。

    您也不需要为解析编写显式容器。 Codable 会自己做。

    您可以简单地解码样本JSON

    if let data = jsonStr.data(using: .utf8)
    {
        let response = try? JSONDecoder().decode(Response.self, from: data)
        print(response?.images)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-05
      • 1970-01-01
      • 1970-01-01
      • 2019-08-05
      • 1970-01-01
      • 2020-04-28
      • 1970-01-01
      相关资源
      最近更新 更多