Pieter
Pieter

Reputation: 2711

Empty return value from swift function containing closure

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?

Upvotes: 0

Views: 1885

Answers (1)

Hossam Ghareeb
Hossam Ghareeb

Reputation: 7123

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.
}

Upvotes: 1

Related Questions