0

I created a function that should return a dictionary filled with data that are retrieved (using json, based on Ray Wenderlich tut) online. That code is in a closure. The problem is that an empty dictionary is returned first, and only afterwards it gets filled. Don't know if this is related to some delay in getting the remote data, but obviously I need the dictionary to be filled first before returning it. Here is the code.

func getStatusFromRemoteSource() -> [StatusModel] {

    var statusUpdates = [StatusModel]()
    println("statusUpdates after initialization: \(statusUpdates)") // 1

    DataManager.getStatusDataWithSuccess { (statusData) -> Void in
        let json = JSON(data: statusData)

        if let jsonArray = json.array {

            for jsonItem in jsonArray {
                var statusVersion: String? = jsonItem["version"].string
                var statusDescription: String? = jsonItem["message"].string
                var statusCode: Int? = jsonItem["code"].string!.toInt()

                var update = StatusModel(version: statusVersion, message: statusDescription, code: statusCode)
                statusUpdates.append(update)
                println("statusUpdates after appending update: \(statusUpdates)") // 3 (after other function call)
            }

            let item = 0
            println("Version \(statusUpdates[item].version) has status \(statusUpdates[item].message)")
            // println("Status code: \(statusUpdates[item].code)")
        }
    }

    println("Status updates before return: \(statusUpdates)")   // 2
    return statusUpdates
}

So //1 prints first, then //2 (still empty) and then the other function (that calls this one) is called. Only then //3 is printed (correctly) with the content that should be retrieved.

How can I fill the statusUpdates dictionary before returning it?

2
  • you should think about using a closure in this case! Commented Apr 26, 2015 at 10:05
  • A function that completes asynchronously cannot return a value, because as you noted, the data hasn't been retrieved yet. You can either supply a closure to the function or invoke another function from the success closure in this function Commented Apr 26, 2015 at 10:10

1 Answer 1

1

You should use Closures in method to return statusUpdates as its Async method. The empty statusUpdates will be returned immediately in your code but when using closures, you can wait till DataManager.getStatusDataWithSuccess is finished:

typealias RemoteStatusHandler = (status:[StatusModel]) -> Void


func getStatusFromRemoteSource(handler:RemoteStatusHandler){

var statusUpdates = [StatusModel]()
println("statusUpdates after initialization: \(statusUpdates)") // 1

DataManager.getStatusDataWithSuccess { (statusData) -> Void in
    let json = JSON(data: statusData)

    if let jsonArray = json.array {

        for jsonItem in jsonArray {
            var statusVersion: String? = jsonItem["version"].string
            var statusDescription: String? = jsonItem["message"].string
            var statusCode: Int? = jsonItem["code"].string!.toInt()

            var update = StatusModel(version: statusVersion, message: statusDescription, code: statusCode)
            statusUpdates.append(update)
            println("statusUpdates after appending update: \(statusUpdates)") // 3 (after other function call)
        }

        let item = 0
        println("Version \(statusUpdates[item].version) has status \(statusUpdates[item].message)")
        // println("Status code: \(statusUpdates[item].code)")
    }

    handler(status: statusUpdates)
}


}

Then your function can be called like this:

getStatusFromRemoteSource { (status) -> Void in
   //use status here, this function is void.
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the code, that helps! One thing though: I call getStatusFromRemoteSource from within a different function and want to bind the [StatusModel] dictionary to a variable. If (in the other function) I do let statusUpdates = getStatusFromRemoteSource { (status) -> Void in ...} it does not work. Guessing that the return type should not be void I changed it into [StatusModel] in both the typalias definition and the function call, but it still won't take it. Any suggestions?
No just use: getStatusFromRemoteSource { (status) -> Void in //use status here } because getStatusFromRemoteSource will be void, doesn't return anything. you will pass to it a block of code.
Thanks a million, it works!! Apparently it takes more time to load the status this way than the direct method used before, but this gets the job done!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.