我正在使用Swift 4.x Codable
。我正在尝试构建一个可以从JSON Struct
解码的response
。
这是JSON
格式
{
"photos": {
"page": 1,
"pages": 22241,
"perpage": 30,
"total": "667205",
"photo": [
{
"id": "44967774371",
"owner": "166588675@N05",
"secret": "db15baa5e6",
"server": "1934",
"farm": 2,
"title": "Olden 3",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44967772021",
"owner": "10194419@N00",
"secret": "f8222b1bfb",
"server": "1956",
"farm": 2,
"title": "OldenCam",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44248382544",
"owner": "158561476@N06",
"secret": "3a98326e64",
"server": "1930",
"farm": 2,
"title": "《極限競速 地平線》開發商擴招177人 打造新3A遊戲",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "31094863798",
"owner": "46322086@N04",
"secret": "efcf829b5a",
"server": "1936",
"farm": 2,
"title": "28-09-18 009",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44248384744",
"owner": "155841463@N08",
"secret": "0727e68d5e",
"server": "1972",
"farm": 2,
"title": "https://irvingcab.com/",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44055514965",
"owner": "151464501@N04",
"secret": "3b24da5ae0",
"server": "1935",
"farm": 2,
"title": "DSC_0166",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "30031052127",
"owner": "166120819@N03",
"secret": "8ee4b48cf6",
"server": "1909",
"farm": 2,
"title": "DSC_0096 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "30031052367",
"owner": "166120819@N03",
"secret": "3fb84e04aa",
"server": "1974",
"farm": 2,
"title": "DSC_0125 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44248375214",
"owner": "166120819@N03",
"secret": "61ffab9bc2",
"server": "1968",
"farm": 2,
"title": "DSC_0075 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44967763341",
"owner": "166120819@N03",
"secret": "94f442fc81",
"server": "1939",
"farm": 2,
"title": "DSC_0050 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "30031051947",
"owner": "166120819@N03",
"secret": "b13231d7a1",
"server": "1928",
"farm": 2,
"title": "DSC_0035 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44248374914",
"owner": "166120819@N03",
"secret": "62c9753fbf",
"server": "1968",
"farm": 2,
"title": "DSC_0122 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "30031051587",
"owner": "166120819@N03",
"secret": "ae4842b58c",
"server": "1915",
"farm": 2,
"title": "DSC_0012 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44967762741",
"owner": "166120819@N03",
"secret": "50d31501b8",
"server": "1953",
"farm": 2,
"title": "DSC_0020 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "30031051107",
"owner": "166120819@N03",
"secret": "5ab647050f",
"server": "1950",
"farm": 2,
"title": "DSC_0111 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "30031050577",
"owner": "166120819@N03",
"secret": "feaac1b5a5",
"server": "1907",
"farm": 2,
"title": "DSC_0152 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44919178682",
"owner": "166120819@N03",
"secret": "be4198c78e",
"server": "1952",
"farm": 2,
"title": "DSC_0104 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "30031050007",
"owner": "166120819@N03",
"secret": "c8d67cfd11",
"server": "1957",
"farm": 2,
"title": "DSC_0108 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44919178542",
"owner": "166120819@N03",
"secret": "7a424ec864",
"server": "1960",
"farm": 2,
"title": "DSC_0036 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44967761961",
"owner": "166120819@N03",
"secret": "202c89c2e4",
"server": "1932",
"farm": 2,
"title": "DSC_0095 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44967761831",
"owner": "166120819@N03",
"secret": "c5ae8f4d24",
"server": "1937",
"farm": 2,
"title": "DSC_0186 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44919178202",
"owner": "166120819@N03",
"secret": "98fdc2beca",
"server": "1978",
"farm": 2,
"title": "DSC_0044 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44919178332",
"owner": "166120819@N03",
"secret": "9f823ae6d4",
"server": "1942",
"farm": 2,
"title": "DSC_0142 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44919178142",
"owner": "166120819@N03",
"secret": "c523b37709",
"server": "1955",
"farm": 2,
"title": "DSC_0028 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44967761661",
"owner": "166120819@N03",
"secret": "291dce4d99",
"server": "1956",
"farm": 2,
"title": "DSC_0061 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "30031049067",
"owner": "166120819@N03",
"secret": "25dfe8ba3b",
"server": "1931",
"farm": 2,
"title": "DSC_0079 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "30031048887",
"owner": "166120819@N03",
"secret": "dc3851bfec",
"server": "1939",
"farm": 2,
"title": "DSC_0065 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44967761591",
"owner": "166120819@N03",
"secret": "878d14b875",
"server": "1926",
"farm": 2,
"title": "DSC_0086 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44967761431",
"owner": "166120819@N03",
"secret": "afe3d46cf2",
"server": "1912",
"farm": 2,
"title": "DSC_0082 (2)",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
}
]
},
"stat": "ok"
}
我只想从JSON响应中解码照片数组
我已经建立了Photo
模型和method
来提取像下面这样的照片阵列
导入基金会
struct Photo: Codable {
let id, owner, secret, server: String?
let farm: Int?
let title: String?
let ispublic, isfriend, isfamily: Int?
}
// MARK: Convenience initializers and mutators
extension Photo {
init(data: Data) throws {
self = try newJSONDecoder().decode(Photo.self, from: data)
}
init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
id: String?? = nil,
owner: String?? = nil,
secret: String?? = nil,
server: String?? = nil,
farm: Int?? = nil,
title: String?? = nil,
ispublic: Int?? = nil,
isfriend: Int?? = nil,
isfamily: Int?? = nil
) -> Photo {
return Photo(
id: id ?? self.id,
owner: owner ?? self.owner,
secret: secret ?? self.secret,
server: server ?? self.server,
farm: farm ?? self.farm,
title: title ?? self.title,
ispublic: ispublic ?? self.ispublic,
isfriend: isfriend ?? self.isfriend,
isfamily: isfamily ?? self.isfamily
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
func flickrURL() -> String{
return "https://farm\(farm!).staticflickr.com/\(server!)/\(id!)_\(secret!).jpg"
}
static func photosFromApi(data: Data) -> [Photo]? {
do {
let decodedData = try newJSONDecoder().decode([String:[String:[Photo]]].self, from: data)
let photos = decodedData["photos"]?["photo"]
return photos
} catch let error{
print("error decoding \(error)")
return nil
}
}
}
问题是我仍然收到错误
error decoding typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [_DictionaryCodingKey(stringValue: "message", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found a string/data instead.", underlyingError: nil))
error decoding typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [_DictionaryCodingKey(stringValue: "message", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found a string/data instead.", underlyingError: nil))
2018-09-28 01:58:46.433353+0800 RxFlickr[10524:281475] [MC] Invalidating cache
2018-09-28 01:59:08.168219+0800 RxFlickr[10524:280957] [MC] Reading from private effective user settings.
error decoding typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [_DictionaryCodingKey(stringValue: "photos", intValue: nil), _DictionaryCodingKey(stringValue: "pages", intValue: nil)], debugDescription: "Expected to decode Array<Any> but found a number instead.", underlyingError: nil))
我认为static func photosFromApi(data: Data) -> [Photo]? {}
的实现存在一些问题。知道为什么我解码后的函数取回一组照片不起作用吗?
答案 0 :(得分:1)
您应该将正确的类型传递给json解码器。我已经将某些属性的类型从double可选更改为仅可选。我添加了newJSONDecoder()
和newJSONEncoder()
,因为您没有在问题中提及它们。而且,我已经声明了一个结构JsonResponse
来简化解码。
结果如下:
let json = """
{
"photos": {
"page": 1,
"pages": 21375,
"perpage": 30,
"total": "641243",
"photo": [
{
"id": "44231730474",
"owner": "130309051@N04",
"secret": "9e12dbee3e",
"server": "1909",
"farm": 2,
"title": "Avio",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44039888945",
"owner": "130309051@N04",
"secret": "7ba28027a9",
"server": "1971",
"farm": 2,
"title": "Avio",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44039885865",
"owner": "130309051@N04",
"secret": "12f38bcfc2",
"server": "1929",
"farm": 2,
"title": "Tailor Made 488",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
{
"id": "44903333472",
"owner": "130309051@N04",
"secret": "dc2d36b45c",
"server": "1901",
"farm": 2,
"title": "Tailor Made 488",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
},
]
}
}
"""
let jsonData = json.data(using: .utf8)!
struct Photo: Codable {
let id, owner, secret, server: String?
let farm: Int?
let title: String?
let ispublic, isfriend, isfamily: Int?
}
struct JsonResponse: Codable {
let page: Int
let pages: Int
let perpage: Int
let total: String
let photo: [Photo]
}
func newJSONDecoder() -> JSONDecoder {
return JSONDecoder()
}
func newJSONEncoder() -> JSONEncoder {
return JSONEncoder()
}
// MARK: Convenience initializers and mutators
extension Photo {
init(data: Data) throws {
self = try newJSONDecoder().decode(Photo.self, from: data)
}
init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
id: String? = nil,
owner: String? = nil,
secret: String? = nil,
server: String? = nil,
farm: Int? = nil,
title: String? = nil,
ispublic: Int? = nil,
isfriend: Int? = nil,
isfamily: Int? = nil
) -> Photo {
return Photo(
id: id ?? self.id,
owner: owner ?? self.owner,
secret: secret ?? self.secret,
server: server ?? self.server,
farm: farm ?? self.farm,
title: title ?? self.title,
ispublic: ispublic ?? self.ispublic,
isfriend: isfriend ?? self.isfriend,
isfamily: isfamily ?? self.isfamily
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
func flickrURL() -> String{
return "https://farm\(farm!).staticflickr.com/\(server!)/\(id!)_\(secret!).jpg"
}
static func photosFromApi(data: Data) -> [Photo]? {
do {
let decodedData = try newJSONDecoder().decode([String:JsonResponse].self, from: data)
if let photos = decodedData.values.first {
return photos.photo
} else {
return []
}
} catch let error{
print("error decoding \(error)")
return nil
}
}
}
Photo.photosFromApi(data: jsonData)