tennis25
tennis25

Reputation: 137

How to get the value of the variable that is assigned in a closure (Swift)

I'm using the Twitter REST API in Swift, and I am trying to get the value of a variable that is assigned inside of a Twitter Request closure, so that I can use that value outside of the closure.

I acquired this code from the Twitter REST API tutorial for Swift, located at: https://dev.twitter.com/twitterkit/ios/access-rest-api

func jsonAvailable() -> Bool {
    // Swift
    let client = TWTRAPIClient()
    let statusesShowEndpoint = "https://api.twitter.com/1.1/statuses/show.json"
    let params = ["id": "20"]
    var clientError : NSError?

    var jsonAvailable: Bool = false
    let request = client.urlRequest(withMethod: "GET", url: 
    statusesShowEndpoint, parameters: params, error: &clientError)

    client.sendTwitterRequest(request) { (response, data, connectionError)-> Void in
    if connectionError != nil {
        print("Error: \(connectionError)")
    }

    do {
        let json = try JSONSerialization.jsonObject(with: data!, options: [])
        print("json: \(json)")
        jsonAvailable = true
    } catch let jsonError as NSError {
        print("json error: \(jsonError.localizedDescription)")
    }

    print("Value of jsonAvailable: \(jsonAvailable)")
    return jsonAvailable
    //always returns false, even if it is changed to true inside of the closure
}

In the last line, jsonAvailable is always false, even when it is changed to true inside of the closure. How can I get the value of jsonAvailable at the end of the function, even as it is modified inside of the sendTwitterRequest closure?

I have tried writing this closure in a separate function and then calling the function to get the value, but because it is a custom closure that requires the client to be called by "sendTwitterRequest" I have found it difficult to pass all these required parameters to fit the API.

Thanks for the help!

Upvotes: 1

Views: 285

Answers (1)

Francis.Beauchamp
Francis.Beauchamp

Reputation: 1373

Your closure is async. What happens is that you go through all the function body before sendTwitterRequest assigns true to jsonAvailable, resulting in jsonAvailable being false. What you need to do is having a callback instead, providing the json status if you'd like (or the json itself as a nillable object).

EDIT: You could have something like this

func jsonAvailable(callback: ((_ isJsonAvailable: Bool) -> Void)) {
    client.sendTwitterRequest(request) { (response, data, connectionError)-> Void in {
        do {
            let json = try JSONSerialization.jsonObject(with: data!, options: [])
            print("json: \(json)")
            callback(true)
        } catch let jsonError as NSError {
            print("json error: \(jsonError.localizedDescription)")
            callback(false)
        }
    }
}

jsonAvailable(callback: { (_ isJsonAvailable: Bool) in
    print(isJsonAvailable)
})

Upvotes: 5

Related Questions