用JSON解码器对JSON数据进行Swift解码[英] Swift - decode JSON data with JSONDecoder

本文是小编为大家收集整理的关于用JSON解码器对JSON数据进行Swift解码的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我正在使用CocktaildB API并遇到一些问题.
我创建了一个从特定类别获取鸡尾酒(每个鸡尾酒的名称和图像)的请求.然后,我尝试使用可解码协议解析JSON.但是它不起作用,并且显示了JSON错误.

因此,我想从以下请求中获取鸡尾酒类别," https://www.thecocktaildb.com/api/json/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结构:

在此处输入图像说明

推荐答案

您需要在此处进行一些其他更改.一个将解码更改为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)
    }
}

和title forheaderInsection方法:

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return drinks[section].strDrink
}

其他推荐答案

错误很明显.而不是阵列(如您的[Drinks].self所示),您会收回字典(将其映射到您的Drinks struct):

drinks = try JSONDecoder().decode(Drinks.self, from: data!)

当然这意味着:

var drinks也变成Drinks(而不是[Drinks])

本文地址:https://www.itbaoku.cn/post/1937800.html

问题描述

I'm working with CocktailDB API and having some problems.
I create a request to get cocktails (each cocktail's name and image) from specific category. Then I try to parse JSON with Decodable protocol. But it doesn't work and JSON Error is displayed.

Therefore I want to get cocktails categories from the following request "https://www.thecocktaildb.com/api/json/v1/1/list.php?c=list" and have a section for each category (display category name in a header) with the cocktails from this section.

My Drink Model:

struct Drinks:Decodable {
    var drinks: [Drink]
}

struct Drink:Decodable {
    var strDrink: String
    var strDrinkThumb: String
}

My Category Model:

struct Categories: Decodable {
    var drinks: [Drink]
}

struct Category: Decodable {
    var strCategory: String
}

My code:

    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 structure:

enter image description here

推荐答案

You need to make a few additional changes here. One change the decoding to Drinks.self. Then reload the tableView. And return the String for the section header. Here's the code:

Decoding:

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)
    }
}

And titleForHeaderInSection method:

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return drinks[section].strDrink
}

其他推荐答案

The error is pretty clear. Instead of an array (as your [Drinks].self implies) you get back a dictionary (that maps to your Drinks struct):

drinks = try JSONDecoder().decode(Drinks.self, from: data!)

which of course means that:

var drinks becomes Drinks as well (instead of [Drinks])