Search code examples
jsonswiftxcodedo-catch

Access variable do-catch statement on Swift


I am developing an application that json parse. I'm using the AlertView for json messages. But I can not access the jsonmessage variable in the AlertView. if I put the AlertView in DO I get this error: "libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)" Sorry for my bad English. This is my code:

request.httpBody = postParameters.data(using: String.Encoding.utf8)
            let task = URLSession.shared.dataTask(with:request as URLRequest){
                data, response, error in
                if error != nil{
                    print("error is \(String(describing: error))")
                    return;
                }

                do {

                    let myJSON =  try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
                    if let parseJSON = myJSON {
                        var jsonmessage : String!
                        jsonmessage = parseJSON["message"] as! String?
                        print(jsonmessage)

                    }
                } catch {

                }
            }
            task.resume()
            let alert = UIAlertController(title: "Alert", message: jsonmessage /*not accessible*/ , preferredStyle: .alert)
        alert.addAction(UIAlertAction(title:"Ok", style:UIAlertActionStyle.default, handler:{ (UIAlertAction) in
            _ = self.navigationController?.popToRootViewController(animated: true)
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "load"), object: nil)
        }))
            self.present(alert, animated: true, completion: nil)

Solution

  • As you have discovered jsonMessage is not accessible from where you are trying to access it.

    This is because of a few reasons:

    1. The request is an asynchronous task that runs in the background and takes some time to complete. So the alert view code actually runs before the jsonMessage is returned

    2. The variable jsonMessage is also out of scope where you are trying to call it.

    To help explain:

    let task = URLSession.shared.dataTask(with:request as URLRequest){
                data, response, error in
    
         let fakeMessage = "hi"
         // data, response, error and fakeMessage only exist here upto the closing bracket. 
    }
    task.resume()
    
    // fakeMessage doesn't exist here at all. 
    

    To resolve your issue you can either present your alert from within the closure (where I have put fakeMessage) or you se a completionHandler to return jsonMessage when it is ready and then show the alert.

    Method 1

    let task = URLSession.shared.dataTask(with:request as URLRequest){
                data, response, error in
                if error != nil{
                    print("error is \(String(describing: error))")
                    return;
                }
    
                do {
    
                    let myJSON =  try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
                    if let parseJSON = myJSON {
                        var jsonmessage : String!
                        jsonmessage = parseJSON["message"] as! String?
    
                        DispatchQueue.main.async {
                             // some helper function to show a basic alert
                             self.presentAlert(title: "Response", message: jsonMessage)
                        }
    
                    }
                } catch {
    
                }
            }
            task.resume()
    

    Method 2

    func fetchSomething(completion: @escaping (String -> Void)?) {
        // setup request
        let task = URLSession.shared.dataTask(with:request as URLRequest){
                data, response, error in
    
         let fakeMessage = "hi"
         completion(fakeMessage)
        }
        task.resume()
    }
    

    then you can use it this way

    self.fetchSomething { response in 
        DispatchQueue.main.async {
            // some helper function to show a basic alert
            self.presentAlert(title: "Response", message: jsonMessage)
        }
    }