这是我需要解码的JSON,下面的链接中提供了它的图片以及文本(格式无法正常工作,因此看起来很难看)。我很确定我用自己的结构正确表示了它。
{ “成功”:{ “总计”:1 }, “内容”:{ “引号”:[ { “ quote”:“上一次不存在。只有这一次。这次一切都将有所不同。只有现在。”, “ author”:“ Bill Murray”, “ length”:“ 118”, “标签”:[ “启发”, “当下” ], “类别”:“启发”, “ title”:“每日励志名言”, “ date”:“ 2019-01-16”, “ id”:null } ], “版权”:“ 2017-19 themsaidso.com” } }
每当我运行我的代码(尝试从JSON中获取字段并将它们存储到变量中以便在UITableView中显示它们)时,它都会失败。我尝试通过使标签显示为带有作者姓名作为标题来对其进行测试。 “作者”是JSON中的一个字段。 这些是代码的重要部分:
Class ViewController: UITableViewController {
...
var quoteArray = [Quote]()
//quoteArray Stores the quote objects that contain the fields I need
.....
//STRUCTS TO REPRESENT THE JSON
struct Quote: Decodable {
let quote: String?
let author: String?
let length: String?
let tags: [String]?
let category: String?
let title: String?
let date: String?
}
struct WebsiteObjectStruct: Decodable {
let success: SuccessStruct
let contents: ContentsStruct
}
struct SuccessStruct: Decodable{
let total: Int?
}
struct ContentsStruct: Decodable{
let quotes: [Quote]?
let copyright: String?
}
.....
//发生解码的功能
fileprivate func fetchJSON(){
...
self.websiteObject = try decoder.decode(WebsiteObjectStruct.self, from: data)
self.tableView.reloadData()
...
}
...
//用于TABLEVIEW的行的行
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cellId")
let authorText = quoteArray[0].author
cell.textLabel?.text = author.text
//For quoteArray we are looking at zero index because in my JSON there
// is ONLY EVER ONE element, located at index 0, in quoteArray
return cell
}
}
该应用程序运行并且tableView为空,它没有作者的名字(在本例中为bill murray)。无论如何,这是错误消息:
解码失败:typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath:[],debugDescription: “打算对数组进行解码,但是找到了一个字典。”, 底层错误:nil))
它表示希望对数组进行解码,但是找到了字典。好吧,我将其更改为一次解码,而不是解码一个数组,而是解码一个结构,并声明了一个变量 在属于struct类型的类中(struct的目的反映了数组的目的)。
简而言之,我将代码稍作更改以适应该结构,并且仅当print语句与解码语句位于相同的编码括号内时,它才可以将作者的姓名打印到控制台。尽管如此,它仍无法将其存储到变量中供使用。
我不认为问题出在数组与字典上,但是控制台谈到了“ underlyingError”,即数组为零。无论变量是什么类型,无论是数组还是Struct,放置在textField中的变量始终为nil。
我收到此错误:
致命错误:展开可选值时意外发现nil
也许是穿线或松动的问题?
更新:此代码有效:
MainNetworkManager类{ //从wep API请求JSON格式
static func fetchJSON(fetchUrl: String, quoteViewController: QuoteViewController) {
let urlString = fetchUrl
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { (data, _, err) in
DispatchQueue.main.async {
if let err = err {
print("Failed to get data from url:", err)
return
}
guard let data = data else { return }
do {
// link in description for video on JSONDecoder
let decoder = JSONDecoder()
// Swift 4.1
decoder.keyDecodingStrategy = .convertFromSnakeCase
//self.webStruct = try decoder.decode(WebsiteObjectStruct.self, from: data)
// self?.quoteArray = quotesArray
// self?.reloadInputViews()
let tempStruct = try decoder.decode(WebsiteObjectStruct.self, from: data)
//print(tempStruct.contents.quotes[0].length)
quoteViewController.webStruct = tempStruct
//quoteViewController.setupLabels(array: (tempStruct.contents.quotes))
quoteViewController.setupLabels(obj: tempStruct)
} catch let jsonErr {
print("Failed to decode:", jsonErr)
}
}
}.resume()
}
答案 0 :(得分:0)
弄清楚您所发布代码的错误有些困难。我认为问题可能出在变量websiteObject
的类型定义上。我创建了一个小操场进行测试,您的结构很好。
我创建了一个可以使用您的结构正常工作的小项目。您可以在这里查看:https://github.com/acyrman/StackOverflow54211226。
相关的更改在fetchJSON函数中。我使用了一个像这样的局部变量:self.websiteObject
,而不是使用我不知道如何定义的let websiteObject = try decoder.decode(WebsiteObjectStruct.self, from: data)
,然后继续获取引号并将其分配给您的quoteArray
变量。
fileprivate func fetchJSON() {
let urlString = "http://quotes.rest/qod.json?category=inspire"
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { [weak self] (data, response, error) in
if error != nil {
self?.displayAlert("Error fetching data: \(String(describing: error?.localizedDescription))")
}
let decoder = JSONDecoder()
do {
guard let data = data else { throw NSError(domain: "this.app", code: -1, userInfo: nil) }
let websiteObject = try decoder.decode(WebsiteObjectStruct.self, from: data)
if let quotesArray = websiteObject.contents.quotes {
DispatchQueue.main.async {
self?.quoteArray = quotesArray
self?.tableView.reloadData()
}
}
} catch let error {
self?.displayAlert("Error decoding json data: \(String(describing: error.localizedDescription))")
}
}.resume()
}
对于该应用程序,我从以下位置获取报价:http://quotes.rest/qod.json?category=inspire。同样在info.plist中,对于启用ATS设置以启用从非https URL提取数据也很重要。
该代码仅用于测试您的结构,不要指望一个干净的代码项目;)
应用使用fetchJSON
单元格样式在viewDidLoad
中调用subtitle
,UI如下所示:
答案 1 :(得分:0)
两个问题。
要使用quoteArray
,您必须复制包含引号的数组
self.websiteObject = try decoder.decode(WebsiteObjectStruct.self, from: data)
self.quoteArray = self.websiteObject.contents.quotes ?? []
DispatchQueue.main.async {
self.tableView.reloadData()
}
在cellForRow
中,您必须通过给定的索引路径来获取项目。然后 出队 该单元格,在Interface Builder中设置样式。
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableview.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath)
let quote = quoteArray[indexPath.row]
cell.textLabel?.text = quote.author
cell.detailTextLabel?.text = quote.quote
return cell
}