Search code examples
jsonswiftasynchronousqueuepriority-queue

Asynchronous JSON request in Swift


I would like to randomize an outlet with randomized questions from a received JSON. Therefore I have to "load" it asynchronously.

************Question edited************************

Why is the Array not "filled"? Also the .count = 0.

@IBAction func refreshBtnTapped(_ sender: UIBarButtonItem) {

    let queue = DispatchQueue(label: "Json loading", qos: .userInteractive)

    self.btnOutlet.isEnabled = false

    func jsonDataRequest () {
        let url = "https://redaktion.pflegonaut.de/service.php"
        let urlObj = URL(string: url)
        URLSession.shared.dataTask(with: urlObj!) { (data, response, error) in
            do {

                // Json to Array
                self.questionsJsonVar = try JSONDecoder().decode([Question].self, from: data!)
                let countOfQuestions = self.questionsJsonVar.count
                print(self.questionsJsonVar)

                // MARK:-- later in queue
                DispatchQueue.main.async {

                    print("main.async")

                    // -- Randomize Question Outlet
                    print("Anzahl der Fragen" , self.countOfQuestions)
// PROBLEM prints "Anzahl der Fragen 0"    
                    let randNumber = Int.random(in: 1 ... self.countOfQuestions)
// PROBLEM therefore upperbound < lowerbound
                    print(self.questionsJsonVar[0].Frage)
// PROBLEM not filled
                    self.questionTextOutlet.text = self.questionsJsonVar[self.randNumber].Frage
// PROBLEM does not work
                }

            } catch {
                print(error)
            }
            }.resume()
    }

    //MARK:-- first in queue
    queue.async {
        jsonDataRequest()
    }

}

Debug Area:

 [R***.Question(ID: "1", Frage: "1", Antwort1: "2", Antwort2: "3", Antwort3: "4", Antwort4: "5", Correct: "1", Notiz: Optional("  1234"), LernsektorID: "0", LerneinheitID: "1", LernbereichID: "1", SchwierigkeitID: "1"),
 R***.Question (ID: "51", Frage: " Welche der drei genannten Werte steuert den Atemantrieb?", Antwort1: "pO2", Antwort2: "pCO2", Antwort3: "pH", Antwort4: "K+", Correct: "2", Notiz: Optional("   Gesteuert wird die Atmung im wesentlichen durch das Gehirn beziehungsweise das Atemzentrum in der Medulla oblongata. Ausschlaggebend ist dabei die Reaktion von Chemorezeptoren auf den Kohlendioxid-Gehalt..."),
 ...
 ...]
 main.async
 Anzahl der Fragen 0

Solution

  • The reason is because the dataTask is asynchronous itself.

    If you want to execute the print("main.async") after the request has returned you need to add the snippet at the end of the response handler. Something like this:

    func jsonDataRequest () {
        let url = "https://redaktion.pflegonaut.de/service.php"
        let urlObj = URL(string: url)
        URLSession.shared.dataTask(with: urlObj!) { (data, response, error) in
            do {
    
                // Json to Array
                self.questionsJsonVar = try JSONDecoder().decode([Question].self, from: data!)
                let countOfQuestions = self.questionsJsonVar.count
                print(self.questionsJsonVar)
    
                // Logic after response has arrived
                DispatchQueue.main.async {
                    print("main.async")
                }
            } catch {
                    print(error)
            }
        }.resume()
    )