I know there is another similar question, but it's for an older version of AFNetworking, and doesn't really answer it anyway.
I have the following code:
AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager];
manager.securityPolicy.allowInvalidCertificates = YES;
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer setAuthorizationHeaderFieldWithUsername: currentUser() password: currentPassword()];
__block NSDictionary* response = nil;
AFHTTPRequestOperation* operation = [manager
GET: #"https://10.20.30.40:8765/foobar"
parameters: [NSDictionary dictionary]
success:^(AFHTTPRequestOperation* operation, id responseObject){
response = responseObject;
NSLog(#"response (block): %#", response);
}
failure:^(AFHTTPRequestOperation* operation, NSError* error){
NSLog(#"Error: %#", error);}
];
[operation waitUntilFinished];
NSLog(#"response: %#", response);
...
If I run this, what I'll see in my log is:
2013-12-09 09:26:20.105 myValve[409:60b] response: (null)
2013-12-09 09:26:20.202 myValve[409:60b] response (block): {
F00005 = "";
F00008 = "";
F00013 = "";
}
The NSLog that is after the waitUntilFinished fires first. I expected it to fire second. What am I missing?
A couple of thoughts:
The issue is that waitUntilFinished will wait for the core network operation to complete, but it will not wait for the success or failure completion blocks. If you want to wait for the completion blocks, you can use a semaphore:
__block NSDictionary* response = nil;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
AFHTTPRequestOperation* operation = [manager GET: #"https://10.20.30.40:8765/foobar"
parameters: [NSDictionary dictionary]
success:^(AFHTTPRequestOperation* operation, id responseObject){
response = responseObject;
NSLog(#"response (block): %#", response);
dispatch_semaphore_signal(semaphore);
}
failure:^(AFHTTPRequestOperation* operation, NSError* error){
NSLog(#"Error: %#", error);
dispatch_semaphore_signal(semaphore);
}];
NSLog(#"waiting");
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// [operation waitUntilFinished];
NSLog(#"response: %#", response);
You can, alternatively, wrap this in your own concurrent NSOperation subclass, posting isFinished in the AFHTTPRequestOperation completion blocks, eliminating the semaphore in the process.
Note, make sure to specify completionQueue if doing semaphores on the main queue
because, in the absence of that, AFNetworking defaults to dispatching completion handlers to the main queue and you can deadlock.
As an aside, you should never block the main queue (poor UX, your app could be killed by watchdog process, etc.), so if you're doing this from the main queue, I'd discourage the use of either waitUntilFinished or the semaphore. It's better to just initiate whatever you need from within the completion blocks, letting the main queue continue execution while this asynchronous network operation is in progress, e.g.:
[activityIndicatorView startAnimating];
AFHTTPRequestOperation* operation = [manager GET: #"https://10.20.30.40:8765/foobar"
parameters: [NSDictionary dictionary]
success:^(AFHTTPRequestOperation* operation, id responseObject){
// do whatever you want with `responseObject` here
// now update the UI, e.g.:
[activityIndicatorView stopAnimating];
[self.tableView reloadData];
}
failure:^(AFHTTPRequestOperation* operation, NSError* error){
// put your error handling here
// now update the UI, e.g.:
[activityIndicatorView stopAnimating];
}];
// NSLog(#"waiting");
// dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// // [operation waitUntilFinished];
// NSLog(#"response: %#", response);
It sounds like you want to let your model let the UI do any necessary updates when the model object is done doing its updates. So, you can use your own block parameters so that the view controller can tell the model object what to do when its done (instead of using waitUntilFinished or semaphore to make the network operation block the main queue). For example, let's assume your model had some method like this:
- (void)updateModelWithSuccess:(void (^)(void))success failure:(void (^)(NSError *error))failure
{
AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager];
manager.securityPolicy.allowInvalidCertificates = YES;
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer setAuthorizationHeaderFieldWithUsername: currentUser() password: currentPassword()];
AFHTTPRequestOperation* operation = [manager GET: #"https://10.20.30.40:8765/foobar"
parameters: [NSDictionary dictionary]
success:^(AFHTTPRequestOperation* operation, id responseObject){
// do your model update here
// then call the success block passed to this method (if any),
// for example to update the UI
if (success)
success();
}
failure:^(AFHTTPRequestOperation* operation, NSError* error){
NSLog(#"Error: %#", error);
// if caller provided a failure block, call that
if (failure)
failure(error);
}];
}
Then your view controller can do something like:
[modelObject updateModelWithSuccess:^{
// specify UI updates to perform upon success, e.g.
// stop activity indicator view, reload table, etc.
} failure:^(NSError *error){
// specify any UI updates to perform upon failure
}]
Bottom line, your code can use the same style of completion blocks that AFNetworking uses. If you want the model to pass information back, you can add additional parameters to the completion blocks, themselves, but I presume the above illustrates the basic idea.
Related
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
I have this bool method that returns a yes or no for an inputted string.
I'm successfully able to return a YES or a NO, but I cannot seem to able to make a network connection and return a YES or a NO depending on the server's response.
I tried using __block and I don't feel like that will wait for the web request to finish, is there a way to return YES or NO in the success block without it giving me the error:
Incompatible block pointer types sending 'BOOL(^)(NSURLSessionTask*__strong, NSError __strong' to parameter of the type 'void(^)(NSURLSessionTask...)
-(BOOL)customResponseForString:(NSString *)text {
__block BOOL response_available;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager.responseSerializer setAcceptableContentTypes:[NSSet setWithObject:#"text/plain"]];
[manager GET:[NSString stringWithFormat:#"http://example.com/response.php?input=%#", text] parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
NSDictionary *response = [NSJSONSerialization JSONObjectWithData:responseObject options:NSUTF8StringEncoding error:nil];
response_available = (BOOL)response[#"response_available"];
if (response_available) {
[session sendTextSnippet:response[#"response"] temporary:NO scrollToTop:NO dialogPhase:#"Summary"];
} else {
response_available = NO;
}
[session sendTextSnippet:[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding] temporary:NO scrollToTop:NO dialogPhase:#"Summary"];
[session sendRequestCompleted];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
//return NO;
}];
});
return response_available;
}
Your block definition syntax is probably erroneous, because you can definitely return a BOOL along other parameters in a block.
- (void)fetchCurrentUserWithCompletion:(void (^)(BOOL success, User *user))completion;
This method would be called like this:
[self.userProfileController fetchCurrentUserWithCompletion:^(BOOL success, User *user) {
if (success) {
NSLog(#"Current User Name: %#", user.fullName);
}
}];
If you use AFNetworking, check the AFHTTPRequestOperation object that handle completionBlocks:
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
User *user = [self userFromResponseObject:responseObject];
if (completion) completion(YES, user);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (completion) completion(NO, user);
}];
Because you are implicitly initializing response_available to NO and then using an async GCD call, your method as written will always immediately return NO without waiting for the request to finish. Note: switching to dispatch_sync won't help either because AFNetworking will queue the GET request asynchronously either way.
Best Approach
Add a completion block argument to customResponseForString:. Then simply execute your completion block in the success or failure blocks of the AFHTTPRequestOperation.
Workable Approach (use caution!)
It is possible to make customResponseForString: wait for a response to the network request, but you will have significant issues if it is ever called from the main thread.
First you create a dispatch group and tell it you are starting some long-running work:
dispatch_group_t networkGroup = dispatch_group_create();
dispatch_group_enter(networkGroup);
Then you need to make your network request and when it completes tell the group that the work is finished with dispatch_group_leave():
[manager GET:[NSString stringWithFormat:#"http://example.com/response.php?input=%#", text] parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
NSDictionary *response = [NSJSONSerialization JSONObjectWithData:responseObject options:NSUTF8StringEncoding error:nil];
response_available = (BOOL)response[#"response_available"];
if (response_available) {
[session sendTextSnippet:response[#"response"] temporary:NO scrollToTop:NO dialogPhase:#"Summary"];
} else {
response_available = NO;
}
[session sendTextSnippet:[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding] temporary:NO scrollToTop:NO dialogPhase:#"Summary"];
[session sendRequestCompleted];
dispatch_group_leave(networkGroup);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
response_available = NO;
dispatch_group_leave(networkGroup);
}];
Before your original method returns, tell it to wait for the entire group to finish processing:
dispatch_group_wait(networkGroup, DISPATCH_TIME_FOREVER);
return response_available;
You could adjust this time interval as needed or leave it at DISPATCH_TIME_FOREVER to let the network request time out on its own.
I am using AFNetworking in this example but I think it pertains more to NSOperation. I have two operations, once is dependent on the other finishing. However op2 really shouldn't run until op1's success block has completely run. In the case of dependencies in an operation queue, op2 will run as soon as op1 is done, but before op1's success block is done.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSURLRequest *request = [manager.requestSerializer requestWithMethod:#"GET" URLString:url parameters: nil error: nil];
NSOperation *op1 = [http.manager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id userLocations) {
NSLog(#"Success");
// do some stuff
// more stuf
// I am done, ready for the next operation.
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
NSOperation* op2 = // create op, this will depend on op1 finishing
[op2 addDependency:Op1]; // op2 is dependent on op1 finishing
[manager.operationQueue addOperations:#[op1, op2] waitUntilFinished:NO];
This does not quite work for me as op2 is dependent on some things that are set in op1's success block. Meaning op2 cannot start until op1 is done with its success block.
Is there a way with NSOperations to queue them such that each can wait until the blocks are done running as well? If not how can I re-design tho accomplish this dependency.
I would structure things a bit differently, setting up the second operation within the first. Like this:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSURLRequest *request = [manager.requestSerializer requestWithMethod:#"GET" URLString:url parameters: nil error: nil];
NSOperation *op1 = [manager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id userLocations) {
NSLog(#"Success");
// do some stuff
// more stuf
// I am done, ready for the next operation.
// SO put the other operation here!
NSOperation* op2 = // create op, this will depend on op1 finishing
[manager.operationQueue addOperation:op2];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[manager.operationQueue addOperation:op1];
I run in to the same problem and found out an excellent solution with just using [operationQueue setSuspended:YES] please see the second answer in this post: NSOperation wait until asynchronous block executes
I have a queue of blocks which perform a webservice call. The problem is that the downloaded data is not freed after the block's end. I read a lot about retains but I can't make ARC dealloc the memory.
Here's the code:
Create the queue of blocks which download the data
- (void)syncData
{
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_async(queue, ^{
[Model syncAziende:^(id response, NSError *error) {
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
[Model syncContatti:^(id response, NSError *error) {
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
[Model syncDestinazioni:^(id response, NSError *error) {
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
and so on...
});
}
On Model.m
+ (void)syncAziende:(RequestFinishBlock)completation
{
__weak typeof(self)selfObject = self;
[selfObject syncData:^(id response, NSError *error) {
completation(response,error);
} wsEndPoint:kCDCEndPointGetAziende tableName:kCDCDBAziendeTableName];
}
+ (void)syncContatti:(RequestFinishBlock)completation
{
__weak typeof(self)selfObject = self;
[selfObject syncData:^(id response, NSError *error) {
completation(response,error);
} wsEndPoint:kCDCEndPointGetContatti tableName:kCDCDBContattiTableName];
}
// and so on...
Where syncData is:
+ (void)syncData:(RequestFinishBlock)completation wsEndPoint:(NSString*) url tableName:(NSString *)table
{
__weak typeof(self)selfObject = self;
[selfObject getDataFromWS:^(id WSresponse, NSError* WSError)
{
completation(nil,nil);
}WSUrl:url];
}
Where getDataFromWS is:
+ (void)getDataFromWS:(RequestFinishBlock)completation WSUrl:(NSString *)svcUrl
{
__weak typeof(self)selfObject = self;
[selfObject getJsonDataFromURL:^(id response, NSError *error)
{
completation(response,error);
}url:svcUrl];
}
Where getJsonDataFromURL is:
+(void)getJsonDataFromURL:(RequestFinishBlock)completation url:(NSString*)url
{
__weak typeof(self)selfObject = self;
__weak AFHTTPRequestOperationManager *manager = [selfObject getAuthorizedRequestionOperationManager];
[manager.requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[manager.requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[manager.requestSerializer setValue:#"gzip" forHTTPHeaderField:#"Accept-Encoding"];
[manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, __weak id responseObject) {
completation([responseObject objectForKey:#"d"],nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
completation(nil,error);
}];
}
These __weak references don't really make sense within the context of a class method. It only makes sense to use the weak-self pattern when dealing with instance methods.
So, this begs the question as to which object you're concerned about not getting released. I don't see anything here that would cause the object that has syncData as an instance method to be retained.
Having said that, this routine with the series of network requests that you have made synchronous through the use of the semaphores would (a) retain any autorelease objects that were instantiated throughout the process (notably, the operations themselves); (b) not allow you to cancel the process once it starts; and (c) run the requests serially (for which you'll pay a serious performance penalty and should be avoided unless you absolutely have to).
I'd suggest a simplification of the code. I'd eliminate the dispatch code with the semaphores. I'd also get rid of all of those weak references to self in class methods.
You should simply issue your GET requests. If you really need them to run serially (as implied by your use of the semaphore), then just set the maxConcurrentOperationCount to 1 for the operationQueue of the AFHTTPRequestOperationManager instance. But don't make them run serially unless you absolutely have to, because you pay a significant performance penalty by doing that. But avail yourself of the NSOperationQueue that AFNetworking provides, rather than also doing your own GCD code (and worse, using semaphores within that GCD code).
But this way, if you want to cancel the requests, you can just call cancelAllOperations for the operationQueue of the AFHTTPRequestOperationManager. You can also control the degree of concurrency with maxConcurrentOperationCount.
Given your description and based on the comments, a naive - but still insufficient -
solution may look as follows:
// A generic completion handler:
typedef void (^completion_t)(id result, NSError* error);
- (void) fetchJSONFromURL:(NSURL*)url completion:(completion_t)completion;
- (void) syncAziendeWithInput:(id)input completion:(completion_t)completion;
- (void) syncContattiWithInput:(id)input completion:(completion_t)completion;
- (void) syncDestinazioniWithInput:(id)input completion:(completion_t)completion;
- (void) syncData
{
dispatch_queue_t sync_queue = dispatch_queue_create("sync_queue", 0); // serial queue
NSURL* url = ...;
[self fetchJSONFromURL:url completion:^(id result, NSError*error){
dispatch_async(sync_queue, ^{
[self syncAziendeWithInput:result completion:^(id result, NSError* error){
...
}];
});
}];
url = ...;
[self fetchJSONFromURL:url completion:^(id result, NSError*error){
dispatch_async(sync_queue, ^{
[self syncContattiWithInput:result completion:^(id result, NSError* error){
...
}];
});
}];
url = ...;
[self fetchJSONFromURL:url completion:^(id result, NSError*error){
dispatch_async(sync_queue, ^{
[self syncDestinazioniWithInput:result completion:^(id result, NSError* error){
...
}];
});
}];
...
}
Caveats:
Oversimplification. A practical solution becomes far more elaborated:
No error handling yet.
No way to cancel the asynchronous tasks.
syncData is asynchronous, but has no completion handler. That is, we don't know when it's complete. We could utilize dispatch_group in order to implement an approach to signal the completion of a number of asynchronous methods.
With the help of a third party library we could implement a solution which does all that above, and looks basically even simpler.
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.