解码的 JSON 字段只给出 nil 值,不能存储到变量中
Decoded JSON fields give only nil values, cannot be stored into variables
这是我需要解码的 JSON,下面的 link 中提供了它的图片以及文本(格式化不起作用,所以它看起来很难看)。我很确定我用我的结构正确地表示了它。
{
"success":{
"total": 1
},
"contents":{
"quotes": [
{
"quote": "The last time doesn't exist. It's only this time. And everything is going to be different this time. There's only now.",
"author": "Bill Murray",
"length": "118",
"tags": [
"inspire",
"present"
],
"category": "inspire",
"title": "Inspiring Quote of the day",
"date": "2019-01-16",
"id": 空
}
],
"copyright":“2017-19 theysaidso.com”
}
}
每当我 运行 我的代码试图从 JSON 中获取字段并将它们存储到变量中以便在 UITableView 中显示它们时,它都会失败。我通过尝试使标签显示为作者姓名作为标题来对其进行测试。
"author" 是 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()
...
}
...
//表格视图函数中行的单元格
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
}
}
应用程序 运行s 和 tableView 是空的,它没有作者的名字(在本例中是 bill murray)。无论如何,这是错误消息:
Failed to decode: typeMismatch(Swift.Array,
Swift.DecodingError.Context(codingPath: [], debugDescription:
"Expected to decode Array but found a dictionary instead.",
underlyingError: nil))
它说它希望解码一个数组,但却找到了一个字典。好吧,我有一次改变它来解码一个结构而不是一个数组,并声明了一个变量
在属于结构类型的 class 中(结构的目的反映了数组的目的)。
简而言之,我稍微更改了代码以适应该结构,并且只有当打印语句与解码语句位于相同的编码括号内时,它才能将作者的姓名打印到控制台。尽管如此,它仍无法将其存储到变量中以供使用。
我不认为问题是 Array vs Dictionary 但是控制台谈到 "underlyingError",Array 是 nil。无论变量是什么类型,无论是 Array 还是 Struct,放入 textField 的变量始终为 nil。
我收到这个错误:
Fatal Error: unexpected found nil while unwrapping optional value
可能是线程或异步问题?
更新:此代码有效:
class MainNetworkManager{
//从wep请求JSON格式API
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()
}
要找出您发布的代码中的错误有点困难。我认为问题可能出在变量 websiteObject
的类型定义上。我创建了一个小操场来测试它,你的结构很好。
我使用您的结构创建了一个可以正常工作的小项目。你可以在这里查看:https://github.com/acyrman/Whosebug54211226.
相关更改在 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.
获取数据也很重要
代码只是为了测试你的结构,不要指望一个干净的代码项目;)
应用程序在 viewDidLoad
中调用 fetchJSON
,使用 subtitle
单元格样式 UI 如下所示:
两个问题。
要使用 quoteArray
,您必须复制包含引号的数组
self.websiteObject = try decoder.decode(WebsiteObjectStruct.self, from: data)
self.quoteArray = self.websiteObject.contents.quotes ?? []
DispatchQueue.main.async {
self.tableView.reloadData()
}
在 cellForRow
中,您必须通过给定的索引路径获取项目。然后dequeue单元格,在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
}
这是我需要解码的 JSON,下面的 link 中提供了它的图片以及文本(格式化不起作用,所以它看起来很难看)。我很确定我用我的结构正确地表示了它。
{ "success":{ "total": 1 }, "contents":{ "quotes": [ { "quote": "The last time doesn't exist. It's only this time. And everything is going to be different this time. There's only now.", "author": "Bill Murray", "length": "118", "tags": [ "inspire", "present" ], "category": "inspire", "title": "Inspiring Quote of the day", "date": "2019-01-16", "id": 空 } ], "copyright":“2017-19 theysaidso.com” } }
每当我 运行 我的代码试图从 JSON 中获取字段并将它们存储到变量中以便在 UITableView 中显示它们时,它都会失败。我通过尝试使标签显示为作者姓名作为标题来对其进行测试。 "author" 是 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()
...
}
...
//表格视图函数中行的单元格
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
}
}
应用程序 运行s 和 tableView 是空的,它没有作者的名字(在本例中是 bill murray)。无论如何,这是错误消息:
Failed to decode: typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))
它说它希望解码一个数组,但却找到了一个字典。好吧,我有一次改变它来解码一个结构而不是一个数组,并声明了一个变量 在属于结构类型的 class 中(结构的目的反映了数组的目的)。
简而言之,我稍微更改了代码以适应该结构,并且只有当打印语句与解码语句位于相同的编码括号内时,它才能将作者的姓名打印到控制台。尽管如此,它仍无法将其存储到变量中以供使用。
我不认为问题是 Array vs Dictionary 但是控制台谈到 "underlyingError",Array 是 nil。无论变量是什么类型,无论是 Array 还是 Struct,放入 textField 的变量始终为 nil。
我收到这个错误:
Fatal Error: unexpected found nil while unwrapping optional value
可能是线程或异步问题?
更新:此代码有效:
class MainNetworkManager{ //从wep请求JSON格式API
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()
}
要找出您发布的代码中的错误有点困难。我认为问题可能出在变量 websiteObject
的类型定义上。我创建了一个小操场来测试它,你的结构很好。
我使用您的结构创建了一个可以正常工作的小项目。你可以在这里查看:https://github.com/acyrman/Whosebug54211226.
相关更改在 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.
获取数据也很重要代码只是为了测试你的结构,不要指望一个干净的代码项目;)
应用程序在 viewDidLoad
中调用 fetchJSON
,使用 subtitle
单元格样式 UI 如下所示:
两个问题。
要使用
quoteArray
,您必须复制包含引号的数组self.websiteObject = try decoder.decode(WebsiteObjectStruct.self, from: data) self.quoteArray = self.websiteObject.contents.quotes ?? [] DispatchQueue.main.async { self.tableView.reloadData() }
在
cellForRow
中,您必须通过给定的索引路径获取项目。然后dequeue单元格,在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 }