这是我的JSON情况
{
"image_id": 11101,
"image_source_id": 9,
"image_author": "",
"image_copyright": "",
"image_format_list": [{
"image_format": {
"image_url": "https://static.musixmatch.com/images-storage/mxmimages/1/0/1/1/1/11101_2.jpg",
"image_format_id": 2,
"width": 150,
"height": 150
}
},
{
"image_format": {
"image_url": "https://static.musixmatch.com/images-storage/mxmimages/1/0/1/1/1/11101_16.jpg",
"image_format_id": 16,
"width": 451,
"height": 500
}
}
]
}
我正确地将自定义对象解码为两个不同的类:MXMImage和MXMImageFormat。但我不知道如何重新编码对象以重建相同的JSON
这是我的代码:
struct MXMImage : Decodable, Encodable, Equatable {
let imageId: Int
let imageSourceId: Int
let imageAuthor: String?
let imageCopyright: String?
let imageFormatList: [MXMImageFormat]?
enum CodingKeys: String, Swift.CodingKey {
case imageId
case imageSourceId
case imageAuthor
case imageCopyright
case imageFormatList
enum ImageFormatListKey: String, CodingKey {
case imageFormat
}
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
imageId = try (container.decodeIfPresent(Int.self, forKey: .imageId) ?? 0)
imageSourceId = try (container.decodeIfPresent(Int.self, forKey: .imageSourceId) ?? 0)
imageAuthor = try? container.decodeIfPresent(String.self, forKey: .imageAuthor)
imageCopyright = try? container.decodeIfPresent(String.self, forKey: .imageCopyright)
var imagesFormatListContainer = try container.nestedUnkeyedContainer(forKey: .imageFormatList)
var imagesList:[MXMImageFormat] = []
while !imagesFormatListContainer.isAtEnd {
let imageFormatContainer = try imagesFormatListContainer.nestedContainer(keyedBy: CodingKeys.ImageFormatListKey.self)
let imageFormat = try? imageFormatContainer.decode(MXMImageFormat.self, forKey: .imageFormat)
if let imageFormat = imageFormat {
imagesList.append(imageFormat)
}
}
self.imageFormatList = imagesList
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(imageId, forKey: .imageId)
try container.encodeIfPresent(imageSourceId, forKey: .imageSourceId)
try container.encodeIfPresent(imageAuthor, forKey: .imageAuthor)
try container.encodeIfPresent(imageCopyright, forKey: .imageCopyright)
var imageContainer = container.nestedUnkeyedContainer(forKey: .imageFormatList)
try imageFormatList?.forEach { imgFormat in
var nested = imageContainer.nestedContainer(keyedBy: CodingKeys.ImageFormatListKey.self)
let data = try imgFormat.encoded()
try nested.encode(data, forKey: .imageFormat)
}
}
}
尤其是,我不知道如何在键image_format
中重新缩进MXMImageFormat对象,然后对自定义数组进行编码。有可能这样做吗?在此先感谢
而不是nestedContainers
,您可以解码/编码[[String:MXMImageFormat]]
数组并映射它
struct MXMImage : Codable, Equatable {
let imageId: Int
let imageSourceId: Int
let imageAuthor: String?
let imageCopyright: String?
let imageFormatList: [MXMImageFormat]?
private enum CodingKeys : String, CodingKey { case imageId, imageSourceId, imageAuthor, imageCopyright, imageFormatList}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
imageId = try container.decode(Int.self, forKey: .imageId)
imageSourceId = try container.decode(Int.self, forKey: .imageSourceId)
imageAuthor = try container.decodeIfPresent(String.self, forKey: .imageAuthor)
imageCopyright = try container.decodeIfPresent(String.self, forKey: .imageCopyright)
if let imageFormatListData = try container.decodeIfPresent([[String:MXMImageFormat]].self, forKey: .imageFormatList) {
imageFormatList = imageFormatListData.compactMap{$0["image_format"]}
} else {
imageFormatList = nil
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(imageId, forKey: .imageId)
try container.encode(imageSourceId, forKey: .imageSourceId)
try container.encodeIfPresent(imageAuthor, forKey: .imageAuthor)
try container.encodeIfPresent(imageCopyright, forKey: .imageCopyright)
if let imageFormatListData = imageFormatList {
try container.encode(imageFormatListData.map{["image_format":$0]}, forKey: .imageFormatList)
}
}
}
struct MXMImageFormat : Codable, Equatable {
let imageUrl : URL
let imageFormatId, width, height : Int
}
假设MXMImageFormat
是这样的:
struct MXMImageFormat : Codable {
let imageUrl: String
let imageFormatId: Int
let width: Int
let height: Int
}
我认为您对此考虑过多。您可以这样做:
try imageFormatList?.forEach { imgFormat in
var nested = imageContainer.nestedContainer(keyedBy: CodingKeys.ImageFormatListKey.self)
try nested.encode(imgFormat, forKey: .imageFormat)
}
因为encode
接受任何Encodable
,包括imgFormat
。实际上,您实际上不需要先转换为Data
(至少这就是您似乎要尝试转换的原因)。
一些测试代码:
let json = """
{
"image_id": 11101,
"image_source_id": 9,
"image_author": "",
"image_copyright": "",
"image_format_list": [{
"image_format": {
"image_url": "https://static.musixmatch.com/images-storage/mxmimages/1/0/1/1/1/11101_2.jpg",
"image_format_id": 2,
"width": 150,
"height": 150
}
},
{
"image_format": {
"image_url": "https://static.musixmatch.com/images-storage/mxmimages/1/0/1/1/1/11101_16.jpg",
"image_format_id": 16,
"width": 451,
"height": 500
}
}
]
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let model = try! decoder.decode(MXMImage.self, from: json)
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
let string = String(data: try! encoder.encode(model), encoding: .utf8)!
print(string) // this should be the same JSON as the one in the string literal
还请注意,在encode
中,您不必在此处使用try?
:
while !imagesFormatListContainer.isAtEnd {
let imageFormatContainer = try imagesFormatListContainer.nestedContainer(keyedBy: CodingKeys.ImageFormatListKey.self)
// here vvvvvvv
let imageFormat = try? imageFormatContainer.decode(MXMImageFormat.self, forKey: .imageFormat)
if let imageFormat = imageFormat {
imagesList.append(imageFormat)
}
}
import Foundation
let jsonData = """
{
"image_id": 11101,
"image_source_id": 9,
"image_author": "",
"image_copyright": "",
"image_format_list": [{
"image_format": {
"image_url": "https://static.musixmatch.com/images-storage/mxmimages/1/0/1/1/1/11101_2.jpg",
"image_format_id": 2,
"width": 150,
"height": 150
}
},
{
"image_format": {
"image_url": "https://static.musixmatch.com/images-storage/mxmimages/1/0/1/1/1/11101_16.jpg",
"image_format_id": 16,
"width": 451,
"height": 500
}
}
]
}
"""
let json = jsonData.data(using: .utf8)!
struct MXMImage: Codable {
var imageId: Int
var imageSourceId: Int
var imageAuthor: String?
var imageCopyright: String?
var imageFormatList: [MXMImageFormat]?
enum CodingKeys: String, CodingKey {
case imageId = "image_id"
case imageSourceId = "image_source_id"
case imageAuthor = "image_author"
case imageCopyright = "image_copyright"
case imageFormatList = "image_format_list"
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
imageId = try container.decode(Int.self, forKey: .imageId)
imageSourceId = try container.decode(Int.self, forKey: .imageSourceId)
imageAuthor = try container.decodeIfPresent(String.self, forKey: .imageAuthor)
imageCopyright = try container.decodeIfPresent(String.self, forKey: .imageCopyright)
if let imageFormatListData = try container.decodeIfPresent([[String:MXMImageFormat]].self, forKey: .imageFormatList) {
imageFormatList = imageFormatListData.compactMap{$0["image_format"]}
} else {
imageFormatList = nil
}
}
}
struct MXMImageFormat: Codable {
var imageUrl: String
var imageFormatId: Int
var width: Int
var height: Int
enum CodingKeys: String, CodingKey {
case imageUrl = "image_url"
case imageFormatId = "image_format_id"
case width = "width"
case height = "height"
}
}
if let results = try? JSONDecoder().decode(MXMImage.self, from: json) {
print(results)
}
打印输出:
MXMImage( imageId: 11101, imageSourceId: 9, imageAuthor: Optional(""), imageCopyright: Optional(""), imageFormatList: Optional([ SwiftPlayground.MXMImageFormat( imageUrl: "https://static.musixmatch.com/images-storage/mxmimages/1/0/1/1/1/11101_2.jpg", imageFormatId: 2, width: 150, height: 150), SwiftPlayground.MXMImageFormat( imageUrl: "https://static.musixmatch.com/images-storage/mxmimages/1/0/1/1/1/11101_16.jpg", imageFormatId: 16, width: 451, height: 500) ]) )
您可以尝试在http://online.swiftplayground.run/中运行它