使用可解码和 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, Swift.DecodingError.Context(codingPath: [], debugDescription: "期望解码 Dictionary 但找到了一个数组。", underlyingError: nil)) .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的主要内容,如果未能解决你的问题,请参考以下文章

使用可解码返回空模型解析 JSON

使用可选值 Swift 4 解码嵌套 JSON

Swift 4 可解码的 json 数组

带有可配置键的 Swift 4 JSON 解码

JSON 的 Swift 可解码解析部分

swift中标准嵌套JSON的可解码包装器