代码之家  ›  专栏  ›  技术社区  ›  Damo

如何在swift中解码json对象的命名数组

  •  1
  • Damo  · 技术社区  · 6 年前

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

    {
        "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类型的,我已经定义了它,并且有一个解码函数,可以解码单个图像对象。图像如下:

    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”或其他方式访问图像数组?

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

    2 回复  |  直到 6 年前
        1
  •  3
  •   Sharad Chauhan Muhammad Bilal Hussain    6 年前

    我认为你的编码结构是错误的。应该是:

    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,URL:“ https://obfuscated.image.url/image1.jpg “” DreamsiteRadio.图像(宽度:800.0,高度:533.0,URL: “ https://obfuscated.image.url/image2.jpg “” DreamsiteRadio.图像(宽度:800.0,高度:478.0,URL: “ https://obfuscated.image.url/image3.jpg “)

        2
  •  1
  •   PGDev    6 年前

    您可以创建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)
    }