Swift - 使用 JSONDecoder 解码 JSON 数据
Posted
技术标签:
【中文标题】Swift - 使用 JSONDecoder 解码 JSON 数据【英文标题】:Swift - decode JSON data with JSONDecoder 【发布时间】:2020-07-14 20:43:15 【问题描述】:我正在使用 CocktailDB API,但遇到了一些问题。 我创建了一个请求以从特定类别中获取鸡尾酒(每种鸡尾酒的名称和图像)。然后我尝试使用 Decodable 协议解析 JSON。但它不起作用并显示 JSON 错误。
因此,我想从以下请求“https://www.thecocktaildb.com/api/json/v1/1/list.php?c=list”中获取鸡尾酒类别,并且每个类别都有一个部分(显示标题中的类别名称)以及本节中的鸡尾酒。
我的饮料模型:
struct Drinks:Decodable
var drinks: [Drink]
struct Drink:Decodable
var strDrink: String
var strDrinkThumb: String
我的类别模型:
struct Categories: Decodable
var drinks: [Drink]
struct Category: Decodable
var strCategory: String
我的代码:
class ViewController: UIViewController
var drinks = [Drinks]()
var categories = [Categories]()
override func viewDidLoad()
super.viewDidLoad()
downloadJSON()
func downloadJSON()
let category = "Cocoa" // for example
let url = URL(string: "https://www.thecocktaildb.com/api/json/v1/1/filter.php?c=\(category)")
URLSession.shared.dataTask(with: url!) (data, response, error) in
if error == nil
do
self.drinks = try JSONDecoder().decode([Drinks].self, from: data!)
print(self.drinks)
catch
print("JSON Error")
.resume()
extension ViewController: UITableViewDataSource, UITableViewDelegate
func numberOfSections(in tableView: UITableView) -> Int
return drinks.count
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
return ""
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return 1
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
return UITableViewCell(style: .default, reuseIdentifier: "cell")
JSON 结构:
【问题讨论】:
而不是毫无意义的"JSON Error"
打印error
实例。它会准确地告诉你哪里出了问题。提示:根对象不是数组。
print(error)
并检查结果。 “JSON 错误”没有任何意义
" typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "期望解码 Array 但找到了一个字典。",底层错误: nil )) "显示错误
试试Categories.self
而不是[Drinks].self
@LeoDabus 不,根据 URL 上的 JSON,它是 Drinks.self
【参考方案1】:
您需要在此处进行一些额外的更改。将解码更改为Drinks.self
。然后重新加载tableView
。并返回节标题的字符串。代码如下:
解码:
var drinks = [Drink]() // modify the drinks property
if let data == data
do
self.drinks = try JSONDecoder().decode(Drinks.self, from: data).drinks
DispatchQueue.main.async
self.tableView.reloadData()
catch
print(error)
还有titleForHeaderInSection方法:
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
return drinks[section].strDrink
【讨论】:
与我的评论同步 ***.com/questions/62903702/… @VeronikaBabii 谢谢!试着让未来的问题更清楚。阅读帖子的人应该了解您所面临的确切问题。【参考方案2】:错误很明显。而不是一个数组(正如你的 [Drinks].self
暗示的那样)你得到一个字典(映射到你的 Drinks
结构):
drinks = try JSONDecoder().decode(Drinks.self, from: data!)
这当然意味着:
var drinks
也变为 Drinks
(而不是 [Drinks]
)
【讨论】:
但是饮料是[饮料],所以我不能将饮料分配给[饮料] ***.com/questions/62903702/… @VeronikaBabii 是的,当然它必须是Drinks
而不是[Drinks]
。我会修改答案。
@VeronikaBabiii 不要强制解包数据。使用警卫guard let data = data else return
@Alladinian 对不起,我应该将消息直接发送给 OP 我没有意识到我在标记你。检查错误是否为 nil 后强制解包是安全的,但不是编写代码的正确方法以上是关于Swift - 使用 JSONDecoder 解码 JSON 数据的主要内容,如果未能解决你的问题,请参考以下文章
使用 JSONDecoder Swift 解码具有整数值的字符串键 [关闭]
Swift4 JSONDecoder 期望解码 Dictionary<String, Any> 但找到了一个数组 [重复]