嵌套在JSON

时间:2018-09-27 18:01:51

标签: arrays json swift4 codable

我正在使用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]? {}的实现存在一些问题。知道为什么我解码后的函数取回一组照片不起作用吗?

1 个答案:

答案 0 :(得分:1)

您应该将正确的类型传递给j​​son解码器。我已经将某些属性的类型从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)