Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift closure with Alamofire

I am making API calls to a server. I am leveraging Alamofire to handle this. I'm trying to create a function that uses Alamofire's GET function to return an object based on a custom class that holds the various outputs provided by this GET function.

It's not clear to me the way in which to do this.

Here's my custom class that will hold details about the response:

import Foundation

class ResponsePackage {

    var success = false
    var response: AnyObject? = nil
    var error: NSError? = nil

}

In another class I have the following function:

func get(apiEndPoint: NSString) -> ResponsePackage {

    let responsePackage = ResponsePackage()

        Alamofire
            .request(.GET, apiEndPoint)
            .responseJSON {(request, response, JSON, error) in
                responsePackage.response = JSON
                responsePackage.success = true
                responsePackage.error = error
        }

    return responsePackage

}

This returns nil as the call to the server is not complete before the return gets executed. I know that I should be able to do this with closures, but I am not sure how to construct this.

like image 259
shawnzizzo Avatar asked Aug 05 '14 14:08

shawnzizzo


2 Answers

The code between the {} is the equivalent of block in objective-C : this is a chunk of code that gets executed asynchronously.

The error you made is where you put your return statement : when you launch your request, the code in {} is not executed until the framework received a response, so when the return statement is reached, chances are, there is still no response. You could simply move the line :

return responsePackage

inside the closure, so the func return only when it has received a response. This is a simple way, but it's not really optimal : your code will get stuck at waiting for the answers. The best way you can do this is by using closure, too. This would look something like :

   func get(apiEndPoint: NSString, completion: (response: ResponsePackage) -> ()) -> Bool {

        let responsePackage = ResponsePackage()
        Alamofire
            .request(.GET, apiEndPoint)
            .responseJSON {(request, response, JSON, error) in
                responsePackage.response = JSON
                responsePackage.success = true
                responsePackage.error = error

                completion(response: responsePackage)
        }
    }
like image 56
Emilie Avatar answered Sep 28 '22 03:09

Emilie


I make an example follow your question about responseJSON with closures:

Follow this little steps:

First of all you can create your custom types in a general class (for example a Constants.swift class):

typealias apiSuccess = (result: NSDictionary?) -> Void
typealias apiProgress = (result: NSDictionary?) -> Void // when you want to download or upload using Alamofire..
typealias apiFailure = (error: NSDictionary?) -> Void

Then in your class:

// Normal http request with JSON response..
func callJSONrequest(url:String, params:[String: AnyObject]?, success successBlock :apiSuccess,
    failure failureBlock :apiFailure) {

        Alamofire.request(.GET, url, parameters: params, encoding: ParameterEncoding.URL)
            .responseJSON { response in
                print("\(response.request?.URL)")  // original URL request
                //print(response.response) // URL response
                //print(response.data)     // server data
                //print(response.result)   // result of response serialization
                if response.result.isSuccess {
                    let jsonDic = response.result.value as! NSDictionary
                    successBlock(result: jsonDic)

                } else {
                    let httpError: NSError = response.result.error!
                    let statusCode = httpError.code
                    let error:NSDictionary = ["error" : httpError,"statusCode" : statusCode]
                        failureBlock(error: error)
                    }
                }
        }
}

func myCommonFunction() {
   let myApiSuccess: apiSuccess = {(result: NSDictionary?) -> Void in 
      print ("Api Success : result is:\n \(result)")
      // Here you can make whatever you want with result dictionary
   }
   let myApiFailure: apiFailure = {(error: NSDictionary?) -> Void in 
      print ("Api Failure : error is:\n \(error)")
      // Here you can check the errors with error dictionary looking for http error type or http status code
   }
   var params :[String: AnyObject]?
   let name : String! = "this is my name"
   let id : String! = "000a"
   params = ["name" : name, "id" : id]
   let url : String! = "https://etc..."
   callJSONrequest(url, params:params, success: myApiSuccess, failure: myApiFailure)
}
like image 41
Alessandro Ornano Avatar answered Sep 28 '22 04:09

Alessandro Ornano