【问题标题】:Swift - decode JSON data with JSONDecoderSwift - 使用 JSONDecoder 解码 JSON 数据
【发布时间】: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

标签: ios json swift api decode


【解决方案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
}

【讨论】:

【解决方案2】:

错误很明显。而不是一个数组(正如你的 [Drinks].self 暗示的那样)你得到一个字典(映射到你的 Drinks 结构):

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

这当然意味着:

var drinks 也变为 Drinks(而不是 [Drinks]

【讨论】:

  • 但是饮料是[饮料],所以我不能将饮料分配给[饮料]
  • @VeronikaBabii 是的,当然它必须是Drinks 而不是[Drinks]。我会修改答案。
  • @VeronikaBabiii 不要强制解包数据。使用警卫guard let data = data else { return }
  • @Alladinian 对不起,我应该将消息直接发送给 OP 我没有意识到我在标记你。检查错误是否为 nil 后强制解包是安全的,但不是编写代码的正确方法
猜你喜欢
  • 2019-02-06
  • 1970-01-01
  • 2020-01-07
  • 2021-08-05
  • 2018-12-19
  • 2019-01-03
  • 2019-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多