Ios Swift JSON解码器';在Flickr的JSON数据中找不到密钥
我在一本书的一个例子中遇到了一个json解码错误。错误显示:Ios Swift JSON解码器';在Flickr的JSON数据中找不到密钥,ios,json,swift,Ios,Json,Swift,我在一本书的一个例子中遇到了一个json解码错误。错误显示: 2021-05-06 07:01:31.193094+1000 Photorama[1562:29734] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed Error fetching interesting photos: keyNotFound(CodingKeys(stringValue: "photos", intVa
2021-05-06 07:01:31.193094+1000 Photorama[1562:29734] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed
Error fetching interesting photos: keyNotFound(CodingKeys(stringValue: "photos", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "photos", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: \"photos\", intValue: nil) (\"photos\").", underlyingError: nil))
然而,在Flickr返回的json数据中,键“photos”确实存在。json数据的缩写副本如下所示:
{
"extra": {
"explore_date": "2021-05-04",
"next_prelude_interval": 57778
},
"photos": {
"page": 1,
"pages": 5,
"perpage": 100,
"total": 500,
"photo": [
{
"id": "51156301899",
"owner": "138752302@N05",
"secret": "31d327f54f",
"server": "65535",
"farm": 66,
"title": "*the power of the sun*",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0,
"datetaken": "2021-04-20 06:52:11",
"datetakengranularity": "0",
"datetakenunknown": "0",
"url_z": "https://live.staticflickr.com/65535/51156301899_31d327f54f_z.jpg",
"height_z": 380,
"width_z": 640
},
"stat": "ok"
}
程序代码如下:
AppDelegate.swift(无更改)
斯威夫特
import UIKit
class PhotosViewController: UIViewController {
@IBOutlet private var imageView: UIImageView!
var store: PhotoStore!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// store.fetchInterestingPhotos()
store.fetchInterestingPhotos {
(photoResult) in
switch photoResult {
case let .success(photos):
print("Successfully found \(photos.count) photos")
case let .failure(error):
print("Error fetching interesting photos: \(error)")
}
}
}
}
斯威夫特
import Foundation
enum EndPoint: String {
case interestingPhotos = "flickr.interestingness.getList"
}
/*
https://api.flickr.com/services/rest/?method=flickr.interestingness.getList
&api_key=a6d819499131071f158fd740860a5a88&extras=url_z,date_taken
&format=json&nojsoncallback=1
*/
struct FlickrAPI {
private static let baseURLString = "https://api.flickr.com/services/rest"
private static let apiKey = "a6d819499131071f158fd740860a5a88"
// assemble url from baseURLString and query items
private static func flickrURL (endPoint: EndPoint, parameters: [String: String]?) -> URL {
var components = URLComponents(string: baseURLString)!
var queryItems = [URLQueryItem]()
let baseParams = [
"method": endPoint.rawValue,
"format": "json",
"nojsoncallback": "1",
"api_key": apiKey
]
for (key, value) in baseParams {
let item = URLQueryItem(name: key, value: value)
queryItems.append(item)
}
if let addtionalParams = parameters {
for (key, value) in addtionalParams {
let item = URLQueryItem(name: key, value: value)
queryItems.append(item)
}
}
components.queryItems = queryItems
return components.url!
}
static var interestingPhotoURL: URL {
// url_z is a URL shortener (zipper) for convenience and beauty
return flickrURL(endPoint: .interestingPhotos,
parameters: ["extras": "url_z,date_taken"])
}
static func photos (fromJSON data: Data) -> Result<[Photo], Error> {
do {
let decoder = JSONDecoder()
let flickrResponse = try decoder.decode(FlickrResponse.self, from: data)
return .success(flickrResponse.photosInfo.photos)
} catch {
return .failure(error)
}
}
}
struct FlickrResponse: Codable {
//let photos: FlickrPhotosResponse
let photosInfo: FlickrPhotosResponse
enum CodingKeys: String, CodingKey {
case photosInfo = "photos"
}
}
struct FlickrPhotosResponse: Codable {
//let photo: [Photo]
let photos: [Photo]
enum CodingKyes: String, CodingKey {
case photos = "photo"
}
}
我想知道问题在哪里以及如何解决。非常感谢你的帮助 json中的
照片
不是数组。它是一个物体
将json粘贴到中以获得正确的可编码对象
// MARK: - FlickrPhotosResponse
struct FlickrPhotosResponse: Codable {
let extra: Extra
let photos: Photos
}
// MARK: - Extra
struct Extra: Codable {
let exploreDate: String
let nextPreludeInterval: Int
enum CodingKeys: String, CodingKey {
case exploreDate = "explore_date"
case nextPreludeInterval = "next_prelude_interval"
}
}
// MARK: - Photos
struct Photos: Codable {
let page, pages, perpage, total: Int
let photo: [Photo]
let stat: String
}
// MARK: - Photo
struct Photo: Codable {
let id, owner, secret, server: String
let farm: Int
let title: String
let ispublic, isfriend, isfamily: Int
let datetaken, datetakengranularity, datetakenunknown: String
let urlZ: String
let heightZ, widthZ: Int
enum CodingKeys: String, CodingKey {
case id, owner, secret, server, farm, title, ispublic, isfriend, isfamily, datetaken, datetakengranularity, datetakenunknown
case urlZ = "url_z"
case heightZ = "height_z"
case widthZ = "width_z"
}
}
尝试将您的API响应粘贴到app.quicktype.io中,并使用生成的代码—您在问题中提供的JSON格式无效。此外,请仅提供需要其他人检查的代码。不需要包括appdelegate、scenedelegate等。如果不需要,您需要学习阅读和解释错误消息,大多数情况下这并不难,对于软件开发人员来说,这是必要的知识
import Foundation
enum EndPoint: String {
case interestingPhotos = "flickr.interestingness.getList"
}
/*
https://api.flickr.com/services/rest/?method=flickr.interestingness.getList
&api_key=a6d819499131071f158fd740860a5a88&extras=url_z,date_taken
&format=json&nojsoncallback=1
*/
struct FlickrAPI {
private static let baseURLString = "https://api.flickr.com/services/rest"
private static let apiKey = "a6d819499131071f158fd740860a5a88"
// assemble url from baseURLString and query items
private static func flickrURL (endPoint: EndPoint, parameters: [String: String]?) -> URL {
var components = URLComponents(string: baseURLString)!
var queryItems = [URLQueryItem]()
let baseParams = [
"method": endPoint.rawValue,
"format": "json",
"nojsoncallback": "1",
"api_key": apiKey
]
for (key, value) in baseParams {
let item = URLQueryItem(name: key, value: value)
queryItems.append(item)
}
if let addtionalParams = parameters {
for (key, value) in addtionalParams {
let item = URLQueryItem(name: key, value: value)
queryItems.append(item)
}
}
components.queryItems = queryItems
return components.url!
}
static var interestingPhotoURL: URL {
// url_z is a URL shortener (zipper) for convenience and beauty
return flickrURL(endPoint: .interestingPhotos,
parameters: ["extras": "url_z,date_taken"])
}
static func photos (fromJSON data: Data) -> Result<[Photo], Error> {
do {
let decoder = JSONDecoder()
let flickrResponse = try decoder.decode(FlickrResponse.self, from: data)
return .success(flickrResponse.photosInfo.photos)
} catch {
return .failure(error)
}
}
}
struct FlickrResponse: Codable {
//let photos: FlickrPhotosResponse
let photosInfo: FlickrPhotosResponse
enum CodingKeys: String, CodingKey {
case photosInfo = "photos"
}
}
struct FlickrPhotosResponse: Codable {
//let photo: [Photo]
let photos: [Photo]
enum CodingKyes: String, CodingKey {
case photos = "photo"
}
}
import Foundation
class PhotoStore {
private let session: URLSession = {
let config = URLSessionConfiguration.default
return URLSession(configuration: config)
}()
private func processPhotosRequest (data: Data?, error: Error?) ->
Result<[Photo], Error> {
guard let jsonData = data else {
return .failure(error!)
}
return FlickrAPI.photos(fromJSON: jsonData)
}
func fetchInterestingPhotos (completion: @escaping (Result<[Photo], Error>) -> Void) {
let url = FlickrAPI.interestingPhotoURL
let request = URLRequest(url: url)
let task = session.dataTask(with: request) {
(data, response, error) in
/*if let jsonData = data {
if let jsonString = String(data: jsonData, encoding: .utf8) {
print(jsonString)
}
} else if let requestError = error {
print("Error fetching interest photos: \(requestError)")
} else {
print("Unexpect error with the request")
}*/
let result = self.processPhotosRequest(data: data, error: error)
completion(result)
}
task.resume()
}
}
import Foundation
class Photo: Codable {
let title: String
let remoteURL: URL
let photoID: String
let dateTaken: Date
public init (title: String, remoteURL: URL, photoID: String, dateTaken: Date) {
self.title = title
self.remoteURL = remoteURL
self.photoID = photoID
self.dateTaken = dateTaken
}
enum CodingKeys: String, CodingKey {
case title
case remoteURL = "url_z"
case photoID = "id"
case dateTaken = "datetaken"
}
}
// MARK: - FlickrPhotosResponse
struct FlickrPhotosResponse: Codable {
let extra: Extra
let photos: Photos
}
// MARK: - Extra
struct Extra: Codable {
let exploreDate: String
let nextPreludeInterval: Int
enum CodingKeys: String, CodingKey {
case exploreDate = "explore_date"
case nextPreludeInterval = "next_prelude_interval"
}
}
// MARK: - Photos
struct Photos: Codable {
let page, pages, perpage, total: Int
let photo: [Photo]
let stat: String
}
// MARK: - Photo
struct Photo: Codable {
let id, owner, secret, server: String
let farm: Int
let title: String
let ispublic, isfriend, isfamily: Int
let datetaken, datetakengranularity, datetakenunknown: String
let urlZ: String
let heightZ, widthZ: Int
enum CodingKeys: String, CodingKey {
case id, owner, secret, server, farm, title, ispublic, isfriend, isfamily, datetaken, datetakengranularity, datetakenunknown
case urlZ = "url_z"
case heightZ = "height_z"
case widthZ = "width_z"
}
}