使用 Codable 解析 JSON 响应会在 swift 中出现错误
Posted
技术标签:
【中文标题】使用 Codable 解析 JSON 响应会在 swift 中出现错误【英文标题】:Parsing JSON response using Codable gives error in swift 【发布时间】:2019-02-09 10:21:56 【问题描述】:我正在尝试使用 Codable 解析 JSON 响应,但它给了我错误。 我试图从下面的堆栈溢出链接中引用,但没有奏效。 how do I parse Any in dictionary using swift
下面是我的代码,不知道哪里错了。
> enum JSONError: String,Error
> case NoData = "ERROR: no data"
> case ConversionFailed = "ERROR: conversion from JSON failed"
>
struct Owner : Decodable
let full_name : String
let html_url:String
let follower:follower
struct follower : Decodable
let followers_url : String
func jsonParser()
let urlPath = "https://api.github.com/search/repositories?q=language:ruby&sort=stars&order=desc"
guard let endpoint = NSURL(string: urlPath) else
print("Error creating endpoint")
return
let request = NSMutableURLRequest(url:endpoint as URL)
URLSession.shared.dataTask(with: request as URLRequest) (data, response, error) in
do
guard let data = data else
throw JSONError.NoData
let jsonResponse = try JSONSerialization.jsonObject(with:
data)
let entries = try! JSONDecoder().decode([Owner].self, from: jsonResponse as! Data)
print(jsonResponse)
catch let error as JSONError
print(error.rawValue)
catch let error as NSError
print(error.debugDescription)
.resume()
我需要从此响应中获取 3 条信息 - 全名、html url 和关注者。 网页接口链接
https://api.github.com/search/repositories?q=language:ruby
请最新查看代码。
以下是错误信息:
'__NSDictionaryI' (0x102965a98) 到 'NSData' (0x102964580)。 2019-02-09 16:17:42.062971+0530 PhotoViewwer[13342:259997] 无法投射值 类型为“__NSDictionaryI”(0x102965a98)到“NSData”(0x102964580)。
谢谢
【问题讨论】:
您遇到了哪个错误? @vadian - 错误消息 - '__NSDictionaryI' (0x102965a98) 到 'NSData' (0x102964580)。 2019-02-09 16:17:42.062971+0530 PhotoViewwer[13342:259997] 无法将“__NSDictionaryI”(0x102965a98)类型的值转换为“NSData”(0x102964580)。 代码中有很多很多错误,请看我的回答。例如,如果您要使用Decodable
,JSONSerialization
行是无意义的。顺便说一句,这会导致错误。
@vadian - 通过你的代码,这样我就会知道我的错误。谢谢瓦迪安。
【参考方案1】:
请学习阅读 JSON。这很容易。集合类型只有两种,数组([]
)和字典()
你的结构错了。
在 JSON 的根字典中有一个字典数组,用于键 items
。
在每个字典中都有键 full_name
和 owner
(这里是 Owner
结构的位置)。
键 follower
的字典不存在。
这些结构正确地表示 JSON
struct Response : Decodable
let items : [Item]
struct Item : Decodable
let fullName : String
let owner : Owner
struct Owner : Decodable
let htmlUrl : URL // URL strings can be decoded directly into URL
let followersUrl : URL
为您的函数添加一个完成处理程序并使用枚举作为结果类型。 failure
案例返回所有 real 错误。 URLRequest
是多余的。只需传递 URL。 JSONSerialization
行毫无意义。
convertFromSnakeCase
策略将 snake_cased 键转换为 camelCased 结构成员
enum Result
case success(Response), failure(Error)
func jsonParser(completion: @escaping (Result) -> Void)
let endpoint = URL(string:"https://api.github.com/search/repositories?q=language:ruby&sort=stars&order=desc")!
URLSession.shared.dataTask(with: endpoint) (data, response, error) in
if let error = error completion(.failure(error)); return
do
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let entries = try decoder.decode(Response.self, from: data!)
completion(.success(entries))
catch
completion(.failure(error))
.resume()
然后叫它
jsonParser result in
switch result
case .success(let entries) : print(entries)
case .failure(let error) : print(error)
如果有本地等价类,则基本上从不使用NS...
类,这里URL
用于NSURL
和URLRequest
用于NS(Mutable)URLRequest
编辑:
在 Swift 5 中,使用原生 Result
类型的语法变得更加方便。它能够转换投掷表达式
罢工>
enum Result
case success(Response), failure(Error)
func jsonParser(completion: @escaping (Result<Response,Error>) -> Void)
let endpoint = URL(string:"https://api.github.com/search/repositories?q=language:ruby&sort=stars&order=desc")!
URLSession.shared.dataTask(with: endpoint) (data, response, error) in
if let error = error completion(.failure(error)); return
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
completion(Result try decoder.decode(Response.self, from: data!) )
.resume()
【讨论】:
以上运行良好,但在一种情况下它失败了。如果全名为 null 它失败,我该如何处理这种情况 - 我希望全名是 nil 而不是在解析 json 时失败。 声明结构成员为可选:let fullName : String?
【参考方案2】:
你需要
func jsonParser()
let urlPath = "https://api.github.com/search/repositories?q=language:ruby&sort=stars&order=desc"
guard let endpoint = NSURL(string: urlPath) else
print("Error creating endpoint")
return
let request = NSMutableURLRequest(url:endpoint as URL)
URLSession.shared.dataTask(with: request as URLRequest) (data, response, error) in
do
let dec = JSONDecoder()
dec.keyDecodingStrategy = .convertFromSnakeCase
let entries = try dec.decode(Root.self, from:data!)
print(entries)
catch
print(error)
.resume()
struct Root : Decodable
let items:[Item]
struct Owner: Codable
let login: String
let id: Int
let nodeId: String
let avatarUrl: String
let gravatarId: String
let url, htmlUrl, followersUrl: String
let followingUrl, gistsUrl, starredUrl: String
let subscriptionsUrl, organizationsUrl, reposUrl: String
let eventsUrl: String
struct Item: Codable
let fullName : String
let htmlUrl:String
let owner: Owner
您不应该在此处将响应转换为数据
from: jsonResponse as! Data)
因为它会崩溃
【讨论】:
以上是关于使用 Codable 解析 JSON 响应会在 swift 中出现错误的主要内容,如果未能解决你的问题,请参考以下文章
Swift Codable:如果 API 将来可能向响应 JSON 添加更多属性,则包括枚举编码键
使用 Alamofire/Codable 解析 JSON 行