Alamofire queue request if previous query is executing - ios

When I send first request and then again I send a second request, Alamofire cancels the first request and gives error as -999 Canceled on it.
What is the way to solve so that both request get processed?
So what I want to do is, user clicks on a button one request is sent, and before that request has completed user clicks on the button again. This behaviour cancels the earlier request, rather what I want it do is, when the button is clicked and the request is sent, it should check whether the previous request is completed or still running. If it is completed then the request should process normally but if the previous request is not completed it should wait for the request to complete and once that is completed this request should be sent
self.alamoFireManager.request(request )
.responseJSON { response in
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
guard response.result.error == nil else {
// got an error in getting the data, need to handle it
print("error calling GET on page")
print(response.result.error!)
print("Failure")
if( response.result.error?.code == -999 )
{
print("Previous Query is still Executing")
return
}

Related

Incorrect response from Alamofire?

I am making a request to a server using Alamofire. Here is how i am doing it:
Alamofire.request(url, method: .post, parameters: [:] ,encoding: JSONEncoding.default).responseJSON { response in
print("response=\(response)")
print("Response=:\((response.response?.statusCode)!)")
switch response.result{
case .success :
let passList = AuthenticateSuccess(nibName: "AuthenticateSuccess", bundle: nil)
self.navigationController?.pushViewController(passList, animated: true)
print("connected")
case .failure(let error):
self.showAlertTost("", msg: "Authentication Failed. Authenticate again!", Controller: self)
}
}
This is what prints:
response=SUCCESS: {
message = "Access denied.";
}
Response=:401
connected
I want to know that if 401 is error why is success block being executed? Is failure case in Alamofire handled differently?
As the documentation says:
By default, Alamofire treats any completed request to be successful, regardless of the content of the response. Calling validate() before a response handler causes an error to be generated if the response had an unacceptable status code or MIME type.
E.g.
Alamofire.request(url, method: .post, encoding: JSONEncoding.default)
.validate()
.responseJSON { response in
...
}
With validate, non 2xx responses will now be treated as errors.
response.success depicts that the server has returned the response. Whereas 401 is something that is related to the REST response which your backend system generated. Hence add the check to response code after verifying that you have received the response to provide better information to the end-user.

Why calls swiftHTTP the response handler if there is no connection?

I'm using swiftHTTP for requesting to my server and when my internet connection is slow, it goes to response part! I've set the example code below:
HTTP.GET("myURL") { response in
let myResponse = response.data // it comes here after the timeout
if response.statusCode == 200 {
//some code
} else {
do {
let jsonError = try JSON(data: myResponse) // in this line it goes to catch because there is no data in myresponse
} catch{
//alert for not having connection
}
}
Why does it call the response function if there's no response?
My server also says, that no request was sent.
It doesn't "go to response", it tries to make the HTTP request as expected and regardless of success or error it's completion handler is called.
The response object that is returned is an object that contains all of the information you need to determine what happened with the request.
So it will contain a timeout status code (HTTP 408), possibly an error message. If it did not respond at all, your app would not be able to handle these cases.
Say for example your user taps on their profile icon in the app and this sends a request to get the users profile, but it timed out. Do you want the user sat waiting, looking at a blank profile screen? It's much better to catch the error and handle it gracefully. In this case you could present a message to the user telling them that something went wrong and close the empty profile screen
Your response handler will also be called from swiftHTTP, if there's no or a very bad connection.To solve this problem, either check if there is an internet connection or check if the data is nil:
HTTP.GET("myURL") { response in
let myResponse = response.data // it comes here after the timeout
if response.statusCode == 200 || response.data == nil {
//some code
} else {
do {
let jsonError = try JSON(data: myResponse) // in this line it goes to catch because there is no data in myresponse
} catch{
//alert for not having connection
}
}
The important part here is the check if response.data == nil.

Session Manager Alamofire Response Data

I try to use Alamofire.SessionManager for retry request and offline manager, and I get problem with catch offile mode.
If I use request like this:
Alamofire.SessionManager.default.request("www.google.pl").responseData(queue: queue) { (data) in
print(data)
}
When is no internet connection, data doesn't print (response Data handler doesn't call) and if it is connected, work perfectly.

NSURLSession 3xx redirects and completion handlers

I have a dataTask + completionHandler approach to downloading data from a web server. So far I have implemented this:
let task = session.dataTaskWithURL(url, completionHandler: {
(pageData,response,error) in
...
...
let code = urlHttpResponse.statusCode
switch code {
case 200:
self.fetchedPages.updateValue(pageData, forKey: pageNumber)
case 404:
self.fetchedPages.updateValue(nil, forKey: pageNumber) //No data exists for that page
default:
self.fetchedPages.updateValue(nil, forKey: pageNumber) //No gurantee data exists for that page
}
NSNotificationCenter.defaultCenter().postNotificationName("pageDataDownloaded", object: self, userInfo: ["numberForDownloadedPage":pageNumber])
What I'm wondering is what happens if statusCode is a 3xx error? Will pageData contain the data at the redirected location? In other words, should I add
case _ where code >= 300 && code < 400:
self.fetchedPages.updateValue(pageData, forKey: pageNumber)
Or will the handler get called again with pageData containing the value at the redirected location and a fresh 200 status code? Or is handling redirects properly something I can only do using a delegate?
If you don't have a delegate or the delegate doesn't implement URLSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:), HTTP redirects will be automatically followed. In that case, you won't see the 30x statuses in your handler.

How to have a completion handler/block after Alamofire Post request?

I have a method which handles a Apple Push Notification Service remote notification. When this method is executed, I want it to call my server and do a HTTP POST request using the Alamofire library. I want to execute another method that will handle the response of the POST request.
The problem for me is that I am using an existing API to fetch a profile from the server in this POST request. So I need to use this existing API and figure out when this profile fetch is specifically triggered from the remote notification.
Since Alamofire requests are done in a background queue, how would I go about doing an execution of a method after receiving the profile back from the server?
What would be a good option to solving this issue?
Thank you!
Since Alamofire requests are done in a background queue, how would I go about doing an execution of a method after receiving the profile back from the server?
Response handling is built in to Alamofire. You can do something like this (adapted from the docs):
Alamofire.request(.POST, "http://httpbin.org/get", parameters: ["foo": "bar"])
.response { (request, response, data, error) in
println(request)
println(response)
println(error)
}
Note the .response method call, which adds a completion handler to the request object; the completion handler is invoked by Alamofire when the request completes (or fails).
It wasn't clear from your question formulation what problem you were trying to solve. But you've clarified your intent in the question comments above.
As I understand the problem now, you're got some code that updates a profile on the server and handles the server's response. The code is called in two contexts, one initiated by a manual request from the user, another initiated by a push notification. In the first case, you don't want to generate an alert after you process the response from the server, but in the second case you do.
You do indeed have a closure that you can use to handle the different behavior even though the difference happens in the asynchronous part of the process. Here's a sketch (not actual working code) of how that might look:
func updateProfile(parameters: [String:String], showAlert: Bool) {
Alamofire.request(.POST, "http://myserver.com/profile", parameters: parameters)
.response { (request, response, data, error) in
if (error == nil) {
processProfileResponse(response)
if showAlert {
showProfileWasUpdatedAlert()
}
}
}
}
Note the showAlert parameter passed in to the updateProfile method. If you pass in true, it calls the showProfileWasUpdatedAlert method to show your alert after receiving the server's response. Note that this boolean value is "captured" by the closure that handles the Alamofire response because the closure was defined inside the updateProfile function.
This, IMHO, is a better approach than declaring an app global inside your AppDelegate.
Here you go
func AlamofireRequest(method: Alamofire.Method, URLString: URLStringConvertible, parameters: [String : AnyObject]?, encoding: ParameterEncoding, headers: [String : String]?) -> Alamofire.Result<String>? {
var finishFlag = 0
var AlamofireResult: Alamofire.Result<String>? = nil
Alamofire.request(method, URLString, parameters: parameters, encoding: encoding, headers: headers)
.responseString { (_, _, result) -> Void in
if result.isSuccess {
finishFlag = 1
AlamofireResult = result
}
else {
finishFlag = -1
}
}
while finishFlag == 0 {
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate.distantFuture())
}
return AlamofireResult
}

Resources