如何在 Swift 中解码一个命名的 json 对象数组
Posted
技术标签:
【中文标题】如何在 Swift 中解码一个命名的 json 对象数组【英文标题】:How to decode a named array of json objects in Swift 【发布时间】: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”或其他方式访问图像数组?
感谢您的阅读,一如既往地感谢您的帮助。
【问题讨论】:
【参考方案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)
【讨论】:
以上是关于如何在 Swift 中解码一个命名的 json 对象数组的主要内容,如果未能解决你的问题,请参考以下文章
Swift:如何将可编码类型作为函数输入传递给编码或解码 json
如何在 Swift 4 中解码 JSON(JSON Web 令牌)?