AFHTTPSessionManager block is not called when app is on background - ios

My app get a silent push, then do some http request in background using AFNetworking,but it didn't enter the complete block, code is:
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] init];
[manager GET:urlString
parameters:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(#"response objece:%#", responseObject);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(#"error:%#", error);
}];
then I found maybe I could use NSURLSessionConfiguration to config the session:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:#"com.company.backgroundDownloadSession"];
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
[manager GET:urlString
parameters:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(#"response objece:%#", responseObject);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(#"error:%#", error);
}];
but AFNetworking crash says:'Terminating app due to uncaught exception 'NSGenericException', reason: 'Data tasks are not supported in background sessions.'
What should I do? And I appreciate your help!

A couple of thoughts:
Proper background NSURLSessionConfiguration requires NSURLSessionDownloadTask or NSURLSessionUploadTask. The GET method, though, creates NSURLSessionDataTask.
To use download or upload tasks, you'll have to build your request separately, and then leverage AFURLSessionManager to issue download or upload. Having said that, you can, though, create requests using the various request serializers, if you're trying to create HTTP GET/POST style requests. Just use the AFHTTPRequestSerializer method requestWithMethod.
For a basic introduction to using AFNetworking in conjunction with background NSURLSessionConfiguration, see https://stackoverflow.com/a/21359684/1271826. You'll have to marry that with the requestWithMethod, discussed above.
Note, be wary about using the task-specific completion blocks (because the tasks continue even if the app is terminated and these blocks are long gone). As the AFNetworking documentation for the background download tasks says:
Warning: If using a background NSURLSessionConfiguration on iOS, these blocks will be lost when the app is terminated. Background sessions may prefer to use setDownloadTaskDidFinishDownloadingBlock: to specify the URL for saving the downloaded file, rather than the destination block of this method.
If you're making a modest request, it may be easier to just ask the OS for a little time to do so if the user happens to leave your app while the request is still in progress. See Executing Finite-Length Tasks section of App Programming Guide for iOS: Background Execution.
Bottom line, before issuing the request, do something like:
UIApplication *application = [UIApplication sharedApplication];
bgTask = [application beginBackgroundTaskWithName:#"MyTask" expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
And then in the completion block of the request, you can terminate the background task:
if (bgTask != UIBackgroundTaskInvalid) {
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}
This is only good for finite length tasks, but it probably much easier than trying to do background NSURLSessionConfiguration.

Related

How to freeze my app to wait for respond?

I have a simple app which try to login users.
User insert username and password
I call a method in another class ->
if ([myBankLogger checkUserLogin:self.memberNumber.text :self.accessCode.text])
{
//Check if user credential is correct
NSLog(#"Corrct");
}
else
{
NSLog(#"Not correct");
}
In checkUserLogin I send a http request to server and it takes a minute to get respond:
-(bool) checkUserLogin :(NSString*)username :(NSString*)password
{
__block bool tmp= false;
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager POST:string parameters:parameters progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(#"JSON: %#", responseObject);
if (responseObject[#"secret_token"])
{
NSLog(#"HERE");
tmp = true;
}
} failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(#"Error: %#", error);
tmp = false;
}];
return tmp;
}
As it is normal compiler dose not wait until it finish processing. It returns false. I researched and found out I must use this:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
// Perform async operation
// Call your method/function here
// Example:
// NSString *result = [anObject calculateSomething];
dispatch_sync(dispatch_get_main_queue(), ^{
// Update UI
// Example:
// self.myLabel.text = result;
});
});
But I am not sure where I should put my code? Appreciate any suggestion or easier solution.
If you perform a synchronous operation on the main thread, this will block the app UI for the entire duration of that sync operation. If it takes too much, the OS will kill the application execution. With an async approach using the dispatch method, you can solve the UI blocking problem:
[self.myRingLoading startAnimating]; // show a ring loading while the following long operation will take (here you are in the main thread scope)
// this dispatch block will move all the actions in an async thread, avoiding any UI blocking issue
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
// Perform here your UI blocking operation
// sample blocking ui operation
NSData* httpDataResult = [NSData dataWithContentsOfURL:#"http://api.yoursite.com/xyz"];
NSString* httpStringResult = [[NSString alloc] initWithData:httpDataResult encoding:NSUTF8StringEncoding];
// this dispatch block will send all action execution to the main queue, commonly the main thread
dispatch_async(dispatch_get_main_queue(), ^(void){
// Perform your UI operation (eg: printing the http response received by the server
[self.myUILabel setText:httpStringResult];
[self.myRingLoading stopAnimating]; // hide the ring loading since the long operation is finished
});
});
There are other native solutions for obtaining the result, for example using the NSOperation and NSOperationQueue. If you use AFNetworking, you can take advantage of several good implementations, for example AFHTTPRequestOperation:
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// Perform your UI actions for the Success case
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Perform your UI actions for the Failed case
}
];
// run the http operation process
[operation start];
Hope it helps

AFHTTPRequestOperationManager doesn't respond

I am using AFNetworking kit to develop an iOS app.
When the app is launching, it requests an access token from the server.
The code is simple as:
__block int status = 0;
[manager GET:url parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject)
{
...fetch access token from response json string
status = 1; //break the loop
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
...networking error
}
and also, to make sure the other requests to the server own the access token, I have put a loop to block the thread until the server responses.
while (status == 0)
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate date]];
}
This worked before, until I imported a third party notification push library. And the async method:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
is continuing print deviceToken request in console and the access token request never responds anything, even the server actually provides the response.
I have been stuck for day, can someone helps me?
UPDATE I have tried to comment the device token stuff, the AFNetworking request still doesn't work, no success no failure and no timeout:
UPDATE2 Clarify my question. AFHTTPRequestOperationManager have sent a GET request to the server, and server responses. But the AFHTTPRequestOperationManager doesn't receive it, and no success no failure callback as well.
A couple of thoughts:
If you're going to use this pattern:
you really should set status to 1 in the error block, too; and
Apple uses distantFuture in its examples, not date:
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
You might have something else blocking the main thread. Try putting a NSLog inside the while loop and see if you see that loop running. If not, then identify where you're blocking the main thread.
Needless to say, this overall pattern is inefficient. I'd suggest employing asynchronous patterns, such as adopting completion handlers in your own code:
- (void)performSomeURL:(NSString *)url completionHandler:(void (^)(NSDictionary *response, NSError *error))completionHandler{
NSDictionary *parameters = ...;
[manager GET:url parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
completionHandler(responseObject, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
completionHandler(nil, error);
}];
}
which could be called like:
[self performSomeURL:url completionHandler:^(NSDictionary *response, NSError *error) {
// use response and error here
}];
// but not here
If you always adopt asynchronous patterns like this in all of your code, never doing anything that blocks the main thread, then not only will your code be more efficient, but you'll never have to fear about deadlocking on the main thread.

Non-unique NSURLSessionDataTask taskIdentifiers

I have an iOS application which is using an NSOperationQueue, NSOperations and AFNetworking 2.1.0 to fire off requests to a server. The -[NSOperation main] method looks something like:
- (void)main {
AFHTTPSessionManager *sessionManager = [AFHTTPSessionManager sharedSessionManager];
[sessionManager GET:#"url"
parameters:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(#"Success");
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(#"Failure");
}
];
}
I have noticed that, from time to time, that the callbacks for a particular operation never get executed, when multiple operations are created and added to the NSOperationQueue in quick succession. I dove into AFNetworking to try to figure out why. I ended up in -[AFURLSessionManager dataTaskWithRequest:completionHandler], which looks like:
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request];
AFURLSessionManagerTaskDelegate *delegate = [AFURLSessionManagerTaskDelegate delegateForManager:self completionHandler:completionHandler];
[self setDelegate:delegate forTask:dataTask];
return dataTask;
}
I added a logging statement right after dataTask is created:
NSLog(#"Task with id %# created for %# on queue %#", #(dataTask.taskIdentifier), request.URL.path, dispatch_get_current_queue());
The log reveals the problem:
2014-02-26 14:11:25.071 App[50094:6a2f] Task with id 15 created for /url1 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:25.071 App[50094:460f] Task with id 16 created for /url2 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:26.274 App[50094:6a2f] Task with id 18 created for /url2 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:26.274 App[50094:6c17] Task with id 17 created for /url1 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:27.546 App[50094:6307] Task with id 20 created for /url2 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:27.546 App[50094:6b17] Task with id 19 created for /url1 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:28.705 App[50094:6b17] Task with id 21 created for /url1 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:28.705 App[50094:6307] Task with id 21 created for /url2 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:32.091 App[50094:6307] Task with id 22 created for /url2 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:32.091 App[50094:6b17] Task with id 23 created for /url1 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
Notice the fourth set in the log has the same taskIdentifier which is what AFNetworking uses to associate tasks with their callbacks, via delegate.
If I force the NSOperations to run on the main queue, then I am unable to recreate the issue - the taskIdentifier is always unique.
Has anyone seen anything like this before? Do I need to ensure that -[NSURLSession dataTaskWithRequest:] runs only on the main thread in order to not get taskIdentifier collisions?
Don't know if this is still relevant to you or not, but this exact thing had me banging my head around all night. Turns out you are partially answering the problem in your question.
As it would turn out, if
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request];
is run asynchronously, then there is the small chance that the instance of NSURLSession will assign the same taskIdentifier to different tasks.
Without forking AFNetworking and synchronizing on all of the dataTaskWithRequest: methods then there were two ways that I could go about fixing this that stood out.
If you don't need the NSURLSessionTask returning from this method then the best way would be to make your own dispatch queue and any requests you want to make with your session manager you just send it to that queue asynchronously like so:
static dispatch_queue_t my_queue;
my_queue = dispatch_queue_create("MyQueueName", DISPATCH_QUEUE_CONCURRENT);
// ... Later, that very same day
dispatch_async(my_queue, ^{
// [sessionManager GET: ...
});
The only problem with this method for your issue however was that it all seemed to be executed on the same operation queue, so maybe this way wouldn't work in your case. The other way (which is how I did it) is actually waay simpler. Just synchronize on the AFURLSessionManager so the invocation of dataTaskWithRequest: can only ever happen synchronously like so:
#synchronized(sessionManager) {
// [sessionManager GET: ...
}
Or, yes, you could just do the task creations on the main thread. But for some projects its not always as simple as that.
I would enqueue a NSURLSessionDataTask to your AFURLSessionManager instead of trying to directly make GET requests. The session manager is intended to abstract the functionality of NSURLSession.
Example:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:#"http://example.com/testapi.php"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(#"error!");
} else {
NSLog(#"task successful!");
}
}];
[dataTask resume];

Multiple AFHTTPClient Request

I've got subclass of AFHTTPClient
The main idea is that i call all API through my singleton of AFHTTPClient subclass, and all requests goes through 1 points for error handling and HUD displaying.
This is entry point for every API calls:
-(void) makeRequestWithPath:(NSString*) path andParams:(NSDictionary*) params
success:(void (^)( id JSON, AFHTTPRequestOperation *operation)) success
failure:(void (^)( NSError *error)) failure
And i've got many methods for API calls something like that:
-(void) getListMainTreeWithSuccess:(void (^)( id JSON, AFHTTPRequestOperation *operation)) success
failure:(void (^)( NSError *error)) failure
{
[self makeRequestWithPath:#"objects/selectlist" andParams:nil success:^(id JSON, AFHTTPRequestOperation *operation) {
success(JSON,operation);
} failure:^(NSError *error) {
failure(error);
}];
}
This works just fine for my needs. But i faced problem that i need to make serial request in loop through my AFHTTPClient subclass and make some action when all of them are finished , I found method
-(void)enqueueBatchOfHTTPRequestOperationsWithRequests:(NSArray *)urlRequests
progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock
completionBlock:(void (^)(NSArray *operations))completionBlock
which should solve my issue, but the problem is that i call all methods through AFHTTPClient and it's methods getPath: and postPath: and previous way forces me to rewrite everything and makes my subclass completely useless, because I need to add there NSArray of AFHTTPRequestoperation, which is not possible to construct or extract from my subclass and my methods. Previously i tried to use __block 's to synchronise requests with semaphore and something else but i failed to get what i need, please help me!
UPDATE:
It seems that it is not possible to even use enqueueBatchOfHTTPRequestOperations method (even with rewriting all my code) because this method needs array of http request operations, but it's not possible to construct POST request with them.
I solved this with an increment/decrement pending download system and tied the HUD to that.
[networkStatus beginNetworkActivity];
[client someRESTActionWithCompletion:^(id object, NSError *error) {
[networkStatus endNetworkActivity];
if (error) {
// Handle the error ...
}
if (![networkStatus hasNetworkActivity]) {
// All downloads have finished
}
}];
I keep the network status object separate which from the AFHTTPClient subclass, but it can be built into the client if that's what you want.
Network status keeps an internal counter. -beginNetworkActivity increments the counter, if the counter was 0, then it displays a HUD. -endNetworkActivity decrements the counter, if the counter becomes 0, then it dismisses the HUD. -hasNetworkActivity returns YES if the counter greater than 0.
Other Notes: I combine the success and failed callbacks into a single completion callback. I keep the network status logic separate from the client because sometime I'll use a singleton network status object, sometimes I'll use a created instance, sometimes I won't use one at all. It all depends on the needs to the higher level logic.
Again, as #MikePollard said, create AFHTTPRequestOperation using
[AFHHTPClient HTTPRequestOperationWithRequest:success:failure:]
For this method create NSURLRequest using (or use another one, pick which one is suitable for you). Here you can also specify, which method to use POST, GET or any other.
[AFHTTPClient requestWithMethod:
path:
parameters:]
After that save all operation to an NSArray, and schedule them using:
[AFHTTPClient enqueueBatchOfHTTPRequestOperationsWithRequests:
progressBlock:
completionBlock:]
Code example:
NSMutableArray *ops = [NSMutableArray new];
NSMutableURLRequest *request1 = [[AFHTTPClient sharedClient] requestWithMethod:#"GET"
path:#"MyEndpoint"
parameters:#{#"key1": #"value"}];
AFHTTPRequestOperation *op1 = [[AFHTTPClient sharedClient] HTTPRequestOperationWithRequest:request1
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success!");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure!");
}];
[ops addObject:op1];
NSMutableURLRequest *request2 = [[AFHTTPClient sharedClient] requestWithMethod:#"POST"
path:#"MyAnotherEndpoint"
parameters:#{#"key2": #(104)}];
AFHTTPRequestOperation *op2 = [[AFHTTPClient sharedClient] HTTPRequestOperationWithRequest:request2
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success!");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure!");
}];
[ops addObject:op2];
[[AFHTTPClient sharedClient] enqueueBatchOfHTTPRequestOperationsWithRequests:ops
progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
NSLog(#"numberOfFinishedOperations: %d totalNumberOfOperations %d",
numberOfFinishedOperations,
totalNumberOfOperations);
}
completionBlock:^(NSArray *operations) {
NSLog(#"All operation compelted!");
}];

How to batch request with AFNetworking 2?

So I'm rewriting an app for iOS 7 with AFNetworking 2.0 and I'm running into the issue of sending a batch of requests at once and tracking their progress. In the old AFNetworking there was the enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock: method on AFHTTPClient, this is clearly refactored out and I'm a bit confused on how to enqueue multiple requests.
I have created a subclass of AFHTTPSessionManager and I'm using the POST:... and GET:... methods to communicate with the server. But I can't find anything in the code and/or docs to enqueue multiple requests at once like with the old AFHTTPClient.
The only thing I can find is the undocumented batchOfRequestOperations:progressBlock:completionBlock: method on AFURLConnectionOperation, but that looks like the iOS 6 way of doing this.
Clearly I'm missing something in the new NSURLSession concept that I should use to batch requests or looking over a new AFNetworking feature. Hope someone can help me on the right track here!
tl;dr: How can I send a batch of requests with my AFHTTPSessionManager subclass?
Thanks Sendoa for the link to the GitHub issue where Mattt explains why this functionality is not working anymore. There is a clear reason why this isn't possible with the new NSURLSession structure; Tasks just aren't operations, so the old way of using dependencies or batches of operations won't work.
I've created this solution using a dispatch_group that makes it possible to batch requests using NSURLSession, here is the (pseudo-)code:
// Create a dispatch group
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i < 10; i++) {
// Enter the group for each request we create
dispatch_group_enter(group);
// Fire the request
[self GET:#"endpoint.json"
parameters:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
// Leave the group as soon as the request succeeded
dispatch_group_leave(group);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
// Leave the group as soon as the request failed
dispatch_group_leave(group);
}];
}
// Here we wait for all the requests to finish
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// Do whatever you need to do when all requests are finished
});
I want to look write something that makes this easier to do and discuss with Matt if this is something (when implemented nicely) that could be merged into AFNetworking. In my opinion it would be great to do something like this with the library itself. But I have to check when I have some spare time for that.
Just updating the thread... I had the same problem and after some researches I found some good solutions, but I decided to stick with this one:
I am using the project called Bolts. So, for the same sample above posted by #Mac_Cain13, it would be:
[[BFTask taskWithResult:nil] continueWithBlock:^id(BFTask *task) {
BFTask *task = [BFTask taskWithResult:nil];
for (int i = 0; i < 10; i++) {
task = [task continueWithBlock:^id(BFTask *task) {
return [self executeEndPointAsync];
}];
}
return task;
}] continueWithBlock:^id(BFTask *task) {
// Everything was executed.
return nil;
}];;
- (BFTask *) executeEndPointAsync {
BFTaskCompletionSource *task = [BFTaskCompletionSource taskCompletionSource];
[self GET:#"endpoint.json" parameters:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
[task setResult:responseObject];
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
[task setError:error];
}];
}];
return task.task;
}
Basically, it's stacking all of the tasks, waiting and unwrapping until there is no more tasks, and after everything is completed the last completion block is executed.
Another project that does the same thing is RXPromise, but for me the code in Bolts was more clear.
For request which can be post or get, you can use AFNetworking 2.0 for batch operation as firstly you need to create operation like this:
//Request 1
NSString *strURL = [NSString stringWithFormat:#"your url here"];
NSLog(#"scheduleurl : %#",strURL);
NSDictionary *dictParameters = your parameters here
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:#"POST" URLString:strURL parameters:dictParameters error: nil];
AFHTTPRequestOperation *operationOne = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operationOne = [AFHTTPResponseSerializer serializer];
[operationOne setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
//do something on completion
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"%#",[error description]);
}];
//Request 2
NSString *strURL1 = [NSString stringWithFormat:#"your url here"];
NSLog(#"scheduleurl : %#",strURL);
NSDictionary *dictParameters1 = your parameters here
NSMutableURLRequest *request1 = [[AFHTTPRequestSerializer serializer] requestWithMethod:#"POST" URLString:strURL1 parameters:dictParameters1 error: nil];
AFHTTPRequestOperation *operationTwo = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
operationTwo = [AFHTTPResponseSerializer serializer];
[operationTwo setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
//do something on completion
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"%#",[error description]);
}];
//Request more here if any
Now perform batch operation like this :
//Batch operation
//Add all operation here
NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:#[operationOne,operationTwo] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations)
{
NSLog(#"%i of %i complete",numberOfFinishedOperations,totalNumberOfOperations);
//set progress here
yourProgressView.progress = (float)numberOfFinishedOperations/(float)totalNumberOfOperations;
} completionBlock:^(NSArray *operations)
{
NSLog(#"All operations in batch complete");
}];
[[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO];
On AFNetworking 2.0, AFHTTPClient has been split on AFHTTPRequestOperationManager and AFHTTPSessionManager, so probably you could start with the first, which has operationQueue property.
Currently, NSURLSession tasks are not suitable for the same kind of patterns request operations use. See the answer from Mattt Thompson here regarding this issue.
Direct answer: if you need dependencies or batches, you'll still need to use request operations.

Resources