0

I have an issue with my closure. From research, I think the issue is that the closure isn't being run before that variable to print is being called. However I don't know how to fix this.

My code is as follows:

    var data: [jsonData.projectSearchJson]?
    let msg: ([jsonData.projectSearchJson]?) -> Void = {
        info in
        data = info
        print(data, "THIS TOO IS DATA") // The data here exists
    }
    
    connection().getProjects(username: username, permission: permission, completion: msg)
    print(data) //Nil is returned
    return data

As you will see with the comments I have added, the code within the call from the closure shows the results. However, when calling the data variable from outside, it doesn't work and returns nil.

The function getProjects works by connecting to the server and then handling the returned JSON. This is the code I am using:

func getProjects(username: String, permission: Int, completion: @escaping ([jsonData.projectSearchJson]?) -> (Void)){
    var project: String = "Fail"
    //Making the connection to the flask server to allow a connection through to the MySQL server
    let url = URL(string: "http://192.168.0.26:8080/getProjects")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    
    let param = ["username": username, "permission": permission] as [String : Any]
    request.httpBody = try? JSONSerialization.data(withJSONObject: param, options: [])
    URLSession.shared.dataTask(with: request) { (data, responce, error) in
        project = String(data: data!, encoding: .utf8)!
        if project == "Invalid"{
            print("Invalid")
        }else{
            let decodedJson = jsonData().projectSearch(jsonString: String(data: data!, encoding: .utf8)!)
            completion(decodedJson)
        }
    }.resume()
}

You may notice that it then calls a json class. This completes the following:

public func projectSearch(jsonString: String) -> [projectSearchJson]?{
    do{
        let jsonData: Data? = jsonString.data(using: .utf8)
        let decode = JSONDecoder()
        let decodedData = try decode.decode([projectSearchJson].self, from: jsonData!)
        
        return decodedData
    }catch{
        print(error, "ERRRRRROROROROROROOROROROR")
        return nil
    }

I use a struct to work on the json and I also use it as the variable type as I believe this is the correct way to do it (the only way I know).

struct projectSearchJson: Codable, Hashable{
    let woid: Int
    let custid: Int
    let staffid: Int
    let name: String
    let description: String
    let startDate: String
    let endDate: String
    let compleate: Int
}

Any help is appreciated. Thanks is advance

JamesMcC
  • 15
  • 5
  • 1
    You've identified the issue correctly - `data` is obtained asynchronously (think of it as being "much later"), so it's not available synchronously. When you have an async function, it cannot return the data synchronously, and same goes for the function that invoked it. It's async all the way up. – New Dev Nov 30 '20 at 19:12
  • @JoakimDanielson I don't think this will work in my situation as I am using JSON brought in over HTTP requests that has then been parsed back to JSON. I have added some more of my code to clarify further. – JamesMcC Nov 30 '20 at 19:25
  • @NewDev Thanks for the reply, what's the difference between the two? – JamesMcC Nov 30 '20 at 19:26
  • This is about asynchronous calls so the link is very relevant. As soon as getProjects has made it request it will return and `print(data)` will be executed and then _after_ this the response will arrive. – Joakim Danielson Nov 30 '20 at 19:36
  • This doesn't work. Tried the linked information – JamesMcC Nov 30 '20 at 20:07

0 Answers0