Reputation: 369
I have a JSON file that is formatted in the following way:
[
{
"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"
}
]
I'm trying to make a structure so that I can load all the questions in my JSON file into my quiz-app. So far from what I've researched from JSON and the new "Decodable" thing apple added I have my Swift code as follows (Note there's a failed attempt commented out):
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
}
}
As you can see from the code comments, that currently gives me a fatal error "found nil while unwrapping". So I assume that the previous line JSONDecoder(). failed horribly.
I am not sure if I am doing this correctly as it's my firs time working with JSONs and I've just been pretty much cookie-cutter following tutorials and posts online. I'd really appreciate some help here. Also the .self after TriviaQuestion was added by the system (I think the problem might be somewhere in there)
Upvotes: 0
Views: 621
Reputation: 10720
As @Oxthor mentioned the typing error,
I just want to add that always use quicktype.io to create your data struct
. You will avoid typos and save your time:
// 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"
}
}
Upvotes: 2
Reputation: 522
You mistyped the category attribute in the TriviaQuestion struct. You have categoroy but it should be category.
Upvotes: 1