使用可解码和 JSON
Posted
技术标签:
【中文标题】使用可解码和 JSON【英文标题】:Using Decodable and JSONs 【发布时间】:2017-11-27 11:42:15 【问题描述】:我有一个格式如下的 JSON 文件:
[
"QID": "B002",
"Stash": "Basic",
"Category": "Geography",
"Question": "What is the highest mountain on earth?",
"Answer": "Mt Everest"
,
"QID": "B003",
"Stash": "Basic",
"Category": "General",
"Question": "What is the gestation period for a pregnant elephant?",
"Answer": "2 years"
]
我正在尝试构建一个结构,以便可以将 JSON 文件中的所有问题加载到我的测验应用程序中。到目前为止,从我从 JSON 和苹果添加的新“可解码”事物中研究的内容来看,我的 Swift 代码如下(请注意,失败的尝试已被注释掉):
var STASHES_SELECTED = ["BasicStash", "MediumStash", "HardStash"]
struct TriviaQuestion: Decodable
let QID: String
let Stash: String
let Categoroy: String
let Question: String
let Answer: String
func loadQuestionStash()
/*
for var i in STASHES_SELECTED
let url = Bundle.main.url(forResource: STASHES_SELECTED[i], withExtension: "JSON") //CANT GET THIS TO WORK!, SAYS CANNOT SUBSCRIPT TYPE [STRING] WITH INDEX TYPE 'STRING'
*/
if let url = Bundle.main.url(forResource: "BasicStash", withExtension: "JSON")
let json = try? Data(contentsOf: url)
let questions = try? JSONDecoder().decode(TriviaQuestion.self, from: json!)
print (questions!) //FATAL ERROR, FOUND NIL
正如您从代码 cmets 中看到的那样,当前给我一个致命错误“展开时发现 nil”。所以我假设上一行 JSONDecoder().惨败。 我不确定我是否正确地执行了此操作,因为这是我第一次使用 JSON,而且我在网上学习教程和帖子时几乎是千篇一律的。我真的很感激这里的一些帮助。 TriviaQuestion 之后的 .self 也是系统添加的(我认为问题可能出在某处)
【问题讨论】:
不要默默地忽略try?
抛出的错误——在do-catch块中使用try
并打印出错误;它会告诉你到底出了什么问题。
另请注意,属性名称为 lowerCamelCase
,而不是 UpperCamelCase
是 Swift 约定。如果您的 JSON 中的键不同,您可以定义自己的 CodingKeys
,比较例如 ***.com/q/44396500/2976878
即使在修正错字之后我仍然收到错误,所以我按照您的建议得到了这个:有一个错误!! typeMismatch(Swift.Dictionary.decode(TriviaQuestion.self
更改为.decode([TriviaQuestion].self
【参考方案1】:
正如@Oxthor 提到的打字错误,
我只想补充一点,始终使用quicktype.io 来创建您的数据struct
。您将避免拼写错误并节省您的时间:
// To parse the JSON, add this file to your project and do:
//
// let triviaQuestion = Array.from(json: jsonString)!
import Foundation
struct TriviaQuestion: Codable
let answer: String
let category: String
let qID: String
let question: String
let stash: String
// MARK: Top-level extensions -
extension Array where Element == TriviaQuestion
static func from(json: String, using encoding: String.Encoding = .utf8) -> [PurpleTriviaQuestion]?
guard let data = json.data(using: encoding) else return nil
return from(data: data)
static func from(data: Data) -> [TriviaQuestion]?
let decoder = JSONDecoder()
return try? decoder.decode([TriviaQuestion].self, from: data)
static func from(url urlString: String) -> [TriviaQuestion]?
guard let url = URL(string: urlString) else return nil
guard let data = try? Data(contentsOf: url) else return nil
return from(data: data)
var jsonData: Data?
let encoder = JSONEncoder()
return try? encoder.encode(self)
var jsonString: String?
guard let data = self.jsonData else return nil
return String(data: data, encoding: .utf8)
// MARK: Codable extensions -
extension TriviaQuestion
enum CodingKeys: String, CodingKey
case answer = "Answer"
case category = "Category"
case qID = "QID"
case question = "Question"
case stash = "Stash"
【讨论】:
这种工具是外星人还没有入侵我们的原因;) 哇,这看起来非常干净和高效。我只是有一个问题。根据上面的评论,它说使用它只是将文件添加到我的项目中并让 triviaQuestion = TriviaQuestion.from(json: jsonString!)。但是复制粘贴该行(并将 jsonString 定义为 json 的 url(我假设)。仍然给我一个错误“Type TriviaQuestion 没有成员“From” 对不起!这可能是 quicktype 的一个错误。试试Array.from
它对我有用
谢谢。我如何定义 jsonString 呢?我以为是 jsonURL 但那不起作用。
在你的情况下,它是字符串形式的文件内容。【参考方案2】:
您在 TriviaQuestion 结构中输入了错误的类别属性。你有 categoroy 但它应该是 category。
【讨论】:
以上是关于使用可解码和 JSON的主要内容,如果未能解决你的问题,请参考以下文章