How to Return Value from Alamofire

How to return value from Alamofire

As mattt points out, Alamofire is returning data asynchronously via a “completion handler” pattern, so you must do the same. You cannot just return the value immediately, but you instead want to change your method to not return anything, but instead use a completion handler closure pattern.

Nowadays, that might look like:

func getOrders(completionHandler: @escaping (Result<[String: Any]>) -> Void) {
performRequest("orders", completion: completionHandler)
}

func performRequest(_ section: String, completion: @escaping (Result<[String: Any]>) -> Void) {
let url = baseURL.appendingPathComponent(section)
let params = ["consumer_key": "key", "consumer_secret": "secret"]

Alamofire.request(url, parameters: params)
.authenticate(user: consumerKey, password: consumerSecret)
.responseJSON { response in
switch response.result {
case .success(let value as [String: Any]):
completion(.success(value))

case .failure(let error):
completion(.failure(error))

default:
fatalError("received non-dictionary JSON response")
}
}
}

Then, when you want to call it, you use this completion closure parameter (in trailing closure, if you want):

api.getOrders { result in
switch result {
case .failure(let error):
print(error)

case .success(let value):
// use `value` here
}
}

// but don't try to use the `error` or `value`, as the above closure
// has not yet been called
//

How i can return value from function use Alamofire

Try to use a handler like this and a callback:

 func getopt(callback:(array: [String]) -> void ){

func completion(request: NSURLRequest?, response:NSHTTPURLResponse?,result:Result<AnyObject>){
if let rdata = result.value{
let data = JSON(rdata)
print(data)
let myArray = [String]
let objects = data.array
for object in objects{
myArray.append(object)
}
callback(myArray)
}
}

let url = "http://www.xxxxxxxxxxxxx.com"
Alamofire.request(.GET,url),
encoding: .JSON).responseJSON(completionHandler: completion)

}

You pass the array to your callback So when you call getopt where you call it you can print the array. Some like this:

func something (){
getopt(callback)
}

func callback(array:[String]){
print array[0]
}

How to return value of array with Alamofire Swift 3?

You should use closures for this purpose:

func getPeople(success: (([Person])->Void)?, failure: ((Error)->Void)?) {
//create Alamofire request
//if everything was fine call success block with people array passed into it
//if failure occurred, call failure block with error.
//In any case you must call either `success` of `failure` here
}

Usage:

ServerManager.sharedInstance.getPeople(
success: { people in
//use people here, update UI if needed
},
failure: { error in
//show an error
})

You can read more about closures in swift here, but I will leave some explanation about your particular case:

Basically, (([Person])->Void)? is a type of the closure. It means that the closure will accepts an array of Person objects and is returning nothing (Void). ? in the end means that it's an optional parameter, so you can pass nil when you call getPeople function if you're not interested in the callback at all.

The same about ((Error)->Void)? failure closure. If you call it, you must pass an Error object to describe what actually went wrong.

Why you closures should be optional?

For example, you have an endpoint for sending user's location to the server. Sometimes you will want to run some code after request is finished and sometimes you don't care if it fails or not (you're just sending the coordinates in background). If you don't need a callback, you can pass an empty closure or nil. In fact there is nothing wrong in using empty closure like { _ in } but it's a bit cleaner if you pass nil. You can meet optional closures in some UIKit methods as well:

present(_:animated:completion:)

animate(withDuration:animations:completion:)

P.S. You can also design your method in such way that it has only one completion callback with two optionals:

func getPeople(completionHandler: (([Person]?, Error?)->Void)?) {}

Personally I prefer two closures because it's more evident and readable, though it's a matter of taste.

Return Alamofire response from a function

The main problem is that Alamofire.request is an asynchronous call, so you will need to use a completion handler, like so

func getStoriesNF (completion: @escaping ([String : Any]?, Error?) {

let parameters: Parameters = ["user_id": userID]

Alamofire.request("https://example.com/stories.php", method: .post, parameters: parameters).validate().responseJSON { response in
switch response.result {
case .success:
if let json = response.result.value {
do {
if let data = try JSONSerialization.jsonObject(with: json as Data, options: .allowFragments) as? [String:Any] {
completion(data, nil)
} catch (let error) {
completion(nil, error)
}
}
}
}
}

JSONSerialization.jsonObject needs to be contained within a try-catch block since it's a throwing call

How to return respond result to function with Alamofire Swift 3

You are not using closures that's why getLastModifiedDate returns nil because it's not returning "Last-Modified" value .You have to use closures if you are doing async task like this

func getLastModifiedDate(completion: @escaping (String) -> ()) {

var date:String?

Alamofire.request("http://www.example.com/apps/demopad/manifest.json")
.response { serverResponse in
date = serverResponse.response?.allHeaderFields["Last-Modified"] as? String
print(date ?? "Server date is nil")
self.lastModifedDateLabel.text = date
completion(date)

}

}

Return value after Alamofire dowloaded data

Your approach is correct. You could use another variable in your closure to see if the request was called properly (or another variable in function, e.g. errorHandler). Example of usage:

downloadImageFromServer(imgURL) { (data1, data2) in
print("Data1: \(data1). Data2: \(data2)")
}

Basic example of adding success/failure variable to your function:

func downloadImageFromServer(imageUrl: String, completionHandler: (Bool, String?, String?) -> ()) {
var myData1 = String()
var myData2 = String()

Alamofire.request(.GET, imageUrl)
.responseImage { response in
switch response.result {
//if user does have a photo
case .Success:
myData1 = //Something
myData2 = //Something else
completionHandler(true, myData1 as? String, myData2 as? String)
case .Failure:
completionHandler(false, nil, nil)
//Print error
}
}
}

Usage of the improved version of downloadImageFromServer():

downloadImageFromServer(imgURL) { (succes, data1, data2) in
if success {
print("Success. Data1: \(data1). Data2: \(data2)")
} else {
print("Error. Data1: \(data1). Data2: \(data2)")
}
}

Return a value from a Alamofire closure

You are correct. It is being returned empty because it is being run on the background thread. When making network requests we therefor tend to use completionBlocks Swift 5 implemented the new typ of Result<Any, Error> which is really convenient.

Try implementing completion((Result<Any, Error>) -> ()) in your function params instead. When you get the response you unwrap it my writing:

switch result {
case .succeses(let data):
//Do something
break
case .failure(let error):
//Do something
break
}

As you are inside the actual block you can't execute a return statement. That's the error you are getting. The block itself doesn't ask for a return. Unlike map, filter, reduce etc.

Returning a value from a function with Alamofire and SwiftyJson

An example of a completion handler for your getMenu function, assuming menu is the value you want to "return":

class MenuManager {

// the handler takes an EKMenu argument
class func getMenu(menu_id: Int, completionHandler: (menu: EKMenu) -> ()) {

let url="https://www.domain.com/arc/v1/api/menus/\(menu_id)/mobile"
Alamofire.request(.GET, url).responseJSON() {
(_, _, data, _) in
println("within menu request")
var json=JSON(data!)
var menu=EKMenu()
menu.name=json["menu"]["name"].stringValue
for (key, subJson) in json["menu"]["menu_headers"]{
EKMenu.processMenuHeaders(subJson)
}

// wrap the resulting EKMenu in the handler
completionHandler(menu)

}
}

class func processMenuHeaders(menu_header: JSON){
let mh_name=menu_header["name"].stringValue
println("mh_name: \(mh_name)")
for (key, subJson) in menu_header["menu_headers"]{
EKMenu.processMenuHeaders(subJson)
}
}

}

MenuManager.getMenu(42, completionHandler: { menu in
// here the handler gives you back the value
println(menu)
})


Related Topics



Leave a reply



Submit