1

I am trying to pass some data from a JSON file using the new(ish) codeable capability in Swift. I have used the below syntax before without issue. I believe I may have something set up wrong, however, as I can't seem to understand why I keep receiving the below message when the JSON format has been approved by a JSON parser.

The error message:

error:dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.})))

The code in my QuestionFactory file...

class QuestionFactory {

func parseJSON(filename fileName: String) -> Quiz? {
    if let url = Bundle.main.url(forResource: fileName, withExtension: "json") {
        print(url)
        do {
            let data = try Data(contentsOf: url)
            let decoder = JSONDecoder()
            print("data received is \(data.count) bytes:\n\(data)")
            print(data)
            print(data as NSData)
            let jsonData = try decoder.decode(Quiz.self, from: data)

            print(jsonData)
        } catch {
            print("error:\(error)")
        }
    }
    return nil
}
}

The code in my initial ViewController:

class LaunchScreen: UIViewController {


  private var quiz: Quiz?
  private let jsonFileName = "QuizData"


 func viewDidLoad() {
    super.viewDidLoad()
    createQuiz()
 }


   private func createQuiz() {
    let questionFactory = QuestionFactory()
    guard let parsedQuiz = questionFactory.parseJSON(filename: jsonFileName) else {
        print("Error creating quiz")
        return
    }
    quiz = parsedQuiz
}

func movesToMainMenuScreen() {
    let transition = CATransition()
    transition.duration = 1.5
    transition.type = kCATransitionFade
    self.navigationController?.view.layer.add(transition, forKey:nil)
    let mainMenuVC: UIViewController = MainMenuViewController(quiz: quiz!) >> I am receiving an error here as well, perhaps due to my mainMenuVC's required init?
    navigationController?.pushViewController(mainMenuVC, animated: false)
}

In my mainMenuViewController:

class mainMenuViewController: UIViewController {

private var quiz: Quiz! {
    didSet {
    tableViewAdapter = AnswerTableViewAdapter(answers: quiz.questions[0].answers) >> Although, it is not obviously reaching this far to read through the JSON.
}

required init(quiz: Quiz) {
    super.init(nibName: nil, bundle: nil)
    defer {
        self.quiz = quiz
    }
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}

The JSON looks like this...

{
"questions":[
             {
             "text": "1. Where will the 2022 World cup be held?",
             "answers": [
                         {
                         "text": "Qatar",
                         "isCorrect": true,
                         "answerType": "2"
                         },
                         {
                         "text": "دولة قطر",
                         "isCorrect": true,
                         "answerType": "1"
                         },
                         {
                         "text": "Jamaica",
                         "isCorrect": false,
                         "answerType": "0"
                         },
                         {
                         "image":"qatarFlag",
                         "isCorrect": true,
                         "answerType": "3"
                         }
                         ]
             }]
}

The Model files....

Quiz.swift

import Foundation

struct Quiz: Decodable {
  var questions: [Question]
}

Question.swift

import Foundation

struct Question: Decodable {
  var text: String
  var answers: [Answer]
}

Answer.swift

import Foundation

struct Answer: Decodable {
  var text: String
  var image: String
  var isCorrect: Bool
  var answerType: String
}
rb2030
  • 416
  • 6
  • 20
  • I think we need to see the JSON string you're decoding when you get the error and also the definition of `Quiz` – Joakim Danielson Jun 08 '18 at 08:43
  • Apologies, I hit submit, before finishing my question. – rb2030 Jun 08 '18 at 08:45
  • 2
    Look at the (NS)data dump. It must start with `<7b` – vadian Jun 08 '18 at 08:49
  • I copy pasted your current JSON in a JSON validator, and it doesn't seem to be valid. You have extra `}]` at the end. Or it is a typo in your sample? – Larme Jun 08 '18 at 08:50
  • As the error suggests - The JSON you are using is invalid. Use https://jsonformatter.org to validate your JSON. – PGDev Jun 08 '18 at 09:59
  • Apologies, I entered in an extra }] by mistake. I have now edited the original question to remove those extra brackets. I printed out the NSData and this is the start of it... data received is 10085 bytes: 10085 bytes 10085 bytes <2f2a200a – rb2030 Jun 08 '18 at 10:16
  • 1
    " <2f2a200a": Your file start with `/* \n` then. You have a header/comment in your file, and there is no comment in JSON (cf https://stackoverflow.com/a/4183018/1801544). Remove it. – Larme Jun 08 '18 at 10:49
  • Argh, so annoying! Thank you!! – rb2030 Jun 08 '18 at 12:35

1 Answers1

0

There is extra

    ]
}

added on last two lines remove these both closing brackets and try to parse JSON.

And make your model's properties to optional to avoid nullable crashes.

The Model files....

Quiz.swift

import Foundation
struct Quiz: Decodable {
    var questions: [Question]?
}

Question.swift

import Foundation
struct Question: Decodable {
  var text: String?
  var answers: [Answer]?
}

Answer.swift

import Foundation
struct Answer: Decodable {
  var text: String?
  var image: String?
  var isCorrect: Bool?
  var answerType: String?
}
sohan vanani
  • 1,537
  • 1
  • 20
  • 37