da1lbi3 da1lbi3 - 1 year ago 110
Swift Question

Return values from completion handler

I want to return the values from an api call.

The call to my api class (I want to get the values in res):

class ViewController: UIViewController {

override func viewDidLoad() {

let t = Api_test();
let res = t.getSomething();


The api class:

import Foundation

class Api_test {

func getAllStations(completionHandler: (response : XMLIndexer) -> ()) {

getRequest { result in
completionHandler(response: SWXMLHash.parse(result))

func getRequest(completionHandler: (result: NSData) -> ()) {
let baseUrl = "http://api.test.com"
let request = NSMutableURLRequest(URL: NSURL(string: baseUrl)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "GET"

let task = session.dataTaskWithRequest(request) {
(data, response, error) in

if data == nil {
print("dataTaskWithRequest error: \(error)")
} else {
completionHandler(result: data!)

Everything works as thought, but I'm stuck at the point to return the values back to the getSomething function. The data is in xml format. How can I get the result set as returned values in the res (viewDidLoad)?

Answer Source

NSURLSession is a fully asynchronous networking API so ideally your view controller should operate correctly and not wait for the data to be returned from the network.

You have three options here:

  1. You can pass a completion block to getSomething and have it pass the result to the block:

    func getSomething(completionHandler: (result: XMLIndexer) -> ()) {
      getRequest { result in
        completionHandler(result: SWXMLHash.parse(result))
    override func viewDidLoad() {
      t.getSomething { res in
  2. If you desperately need the XML data in hand before view is displayed onto screen, you can make the main thread wait till network operation finishes executing. You can use dispatch_semaphore_t:

    func getSomething() -> XMLIndexer? {
      var xml: XMLIndexer? = nil
      let semaphore: dispatch_semaphore_t = dispatch_semaphore_create(0)
      getRequest { result in
        xml = SWXMLHash.parse(result)
      dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
      return xml
  3. Last option is, you can use another 3rd party that does the parsing synchronously. There is a great one named Ono:

    var error: NSError?
    let xml = ONOXMLDocument(data: result, error: &error)