EDIT: The highlighted row in the screenshot is what I have a problem with, why is NSURLConnection running on [NSThread main] when I'm not calling it, AFNetworking is.
I'm using AFNetworking for my project, but when running Time Profiler in Instruments I'm seeing a lot of activity on the main thread for NSURLConnection, I have a feeling this is not what I want.
My method is
- (void)parseArticles {
NSMutableArray *itemsToParse = [[FMDBDataAccess sharedDatabase] getItemsToParse];
NSMutableArray *operations = [[NSMutableArray alloc] init];
for (Post *p in itemsToParse) {
NSMutableString *strURL = [NSMutableString new];
[strURL appendString:#"http://xxxxxxxxxxxxxxxxxxxxxx.php?url="];
[strURL appendString:[p href]];
NSURL *url = [NSURL URLWithString:strURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[[ParserClient sharedInstance] registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
dispatch_async(loginParseQueue, ^{
Parser *parse = [[Parser alloc] init];
[parse parseLink:responseObject rowID:[p rowID]];
});
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"%#",error);
}];
[operations addObject:operation];
}
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
[operationQueue setMaxConcurrentOperationCount:3];
[operationQueue addOperations:operations waitUntilFinished:NO];
}
Why would AFNetworking be using the main thread? and how do I fix it.
AFNetworking is running on a child thread not in main thread, but every thread has a main method, which is on the image you post. This is not the main thread.Now tell me What do you want to fix?
It's because AFNetworking uses "successCallbackQueue" to route the completion block :
AFHTTPRequestOperation.m :
self.completionBlock = ^{
if (self.error) {
if (failure) {
dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error);
});
}
} else {
if (success) {
dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{
success(self, self.responseData);
});
}
}
};
You can simply assign a different thread to success and failure completion blocks :
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.name.bgqueue", NULL);
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.successCallbackQueue = backgroundQueue;
operation.failureCallbackQueue = backgroundQueue;
EDIT:
Here is some code to run operations in a background thread. Use of any function called from the UI thread will run on on the UI thread. You can use a technique similar to the one specified below to run your operation on a background thread, and then dispatch the result back to the UI thread for later use.
Here is the technique I used, you may replace my sendSynchronousRequest call with your AFHTTPRequestOperation :
Specify a special type (a block) so you can pass blocks of code around.
typedef void (^NetworkingBlock)(NSString* stringOut);
Then, you need to dispatch to a background thread, so as not to freeze your UI thread.
Here's a function to call stuff in a background thread, and then wait for a response, and then call a block when done without using the UI thread to do it:
- (void) sendString:(NSString*)stringIn url:(NSString*)url method:(NSString*)method completion:(NetworkingBlock)completion {
//build up a request.
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
NSData *postData = [stringIn dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPMethod:method];
[request setValue:[NSString stringWithFormat:#"%d", postData.length] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"]; //or whatever
[request setHTTPBody:postData];
//dispatch a block to a background thread using GCD (grand central dispatch)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURLResponse *response;
NSError* error;
//request is sent synchronously here, but doesn't block UI thread because it is dispatched to another thread.
NSData* responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
//call complete, so now handle the completion block.
if (completion) {
//dispatch back to the UI thread again
dispatch_async(dispatch_get_main_queue(), ^{
if (responseData == nil) {
//no response data, so pass nil to the stringOut so you know there was an error.
completion(nil);
} else {
//response received, get the content.
NSString *content = [[NSString alloc] initWithBytes:[responseData bytes] length:responseData.length encoding:NSUTF8StringEncoding];
NSLog(#"String received: %#", content);
//call your completion handler with the result of your call.
completion(content);
}
});
}
});
}
Use it like this:
- (void) myFunction {
[self sendString:#"some text in the body" url:#"http://website.com" method:#"POST" completion:^(NSString *stringOut) {
//stringOut is the text i got back
}];
}
Related
I am trying to update my custom label using GCD however all I am getting is the text I initialized the label with:
-(void)drawCardInfo{
__block NSString *cardString;
PPLinearLayoutLabelItem *cardDetails = [[PPLinearLayoutLabelItem alloc] initWithText:#"CREDIT CARD INFO" font:[PPFonts regular18] maxWidth:[LayoutValues getMaxWidthClipped]];
[cardDetails setPaddingTop:20];
[cardDetails setPaddingBottom:10];
[self.topContainerContent addObject:cardDetails];
PPLinearLayoutLabelItem *cardInfo = [[PPLinearLayoutLabelItem alloc] initWithText:#"Data" font:[PPFonts bold16] maxWidth:[LayoutValues getMaxWidthClipped]];
[cardInfo setPaddingTop:0];
[self.topContainerContent addObject:cardInfo];
LinearLayoutHorizontalLine *line1 = [[LinearLayoutHorizontalLine alloc] initWithMaxWidth:[LayoutValues getMaxWidthClipped]];
[self.topContainerContent addObject:line1];
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSOperationQueue *networkQueue = [[NSOperationQueue alloc] init];
networkQueue.maxConcurrentOperationCount = 5;
NSURL *url = [NSURL URLWithString:#"https://xxxxxxxxxxxxxxxxxx"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *string = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
if([string isEqualToString:#""]){
} else {
NSMutableDictionary *dict=[NSJSONSerialization JSONObjectWithData:[string dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
NSString *cardType = [dict objectForKey:#"credit_card_type"];
NSString *cardFinalFour = [dict objectForKey:#"credit_card_last_4"];
cardString = [NSString stringWithFormat:#"%# **** %#",cardType, cardFinalFour];
NSLog(#"%#",cardString);
}
dispatch_async(dispatch_get_main_queue(), ^{ [cardInfo setText:cardString]; });
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"%s: AFHTTPRequestOperation error: %#", __FUNCTION__, error);
}];
[networkQueue addOperation:operation];
});
}
I am successfully logging out the value proving that the network call works fine on a separate thread. Still my label is not being updated. How can I mitigate this?
Looks like you are trying to update the text for the label in a background thread. Updating UI elements on anywhere other than the main thread is not such a good idea since you never know when a asynchronous job will finish.
You can use the following ways to go about it:
Get the main thread and then update the text label
dispatch_async(dispatch_get_main_queue(), ^{
//Code here to which needs to update the UI in the UI thread goes here
});
Use dispatch_sync
Use NSOperations with dependancies (This will be the longest)
I have a large NSArray I am wanting to split into chunks and send to my web server, upon completion of each chunk I then need to update the fields in my SQLite DB that relate to each item in each array chunk.
This is the code I am currently running, where I try to use a call back to receive success or failure then update my local SQLite DB where appropriate.
- (void)postlowData:(NSArray *)lowMArray Callback:(void (^)(NSError *error, BOOL success))callback;
{
// Currently this method is sending the whole lowMArray
// What I want to do is Split lowMArray into a chunkArray (where chunk is 20 of the leading items from lowMArray)
// I would then send chunkArray with the following code, when I receive a response I then want to update local SQLite DB with result and recall this method to start on the next 20 chunks.
// Create Json data from lowMArray
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:lowMArray
options:NSJSONWritingPrettyPrinted
error:nil];
// Construct post request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#/lows", _silServerBaseUrl]]];
request = [self applyAuth:request];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json; charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:jsonData];
// Send post request
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
// NSLog(#"Response Failed!");
callback(error, NO);
} else {
// NSLog(#"Response Success!");
callback(error, YES);
// On success add itmes from lowChunkArray so that you can adjust sent_Flag later
}
}];
[dataTask resume]; // runs task
}
The issue I am running into is that when I run this code if I am splitting the array into chunks sending the chunk adjusting the main array for the next chunk I don't get a confirmed callback till the very end of all the requests, at which point I have lost track of what success or failure?
Maybe I am going about this the wrong way?
Update
I am now trying to do this using AFHTTPRequestOperation which seems to be working as a batch upload however the
setHTTPBody:jsonData
Never seems to make it to the server.
I used this Batch of Operations example to help me construct this method however as I said above the JSON data never makes it to the server.
- (void)postlowData:(NSArray *)lowMArray;
{
NSLog(#"Syncing Local");
NSArray *chunklow = [[NSArray alloc] init];
NSMutableArray *mutableOperations = [NSMutableArray array];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/lows", _silServerBaseUrl]];
//Test: creating 10 things to send
for (int i = 0; i < 10; i++) {
if ([lowMArray count] > 0) {
if ([lowMArray count] >= 20) {
low = [lowMArray subarrayWithRange:NSMakeRange(0, 20)];
} else if ([lowMArray count] < 20) {
low = [lowMArray subarrayWithRange:NSMakeRange(0, [lowMArray count])];
}
}
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:low
options:NSJSONWritingPrettyPrinted
error:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request = [self applyAuth:request];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json; charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:jsonData];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[mutableOperations addObject:operation];
}
NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:mutableOperations progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
NSLog(#"%lu of %lu complete", numberOfFinishedOperations, totalNumberOfOperations);
} completionBlock:^(NSArray *operations) {
NSLog(#"All operations in batch complete");
NSLog(#"Syncing complete");
}];
[[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO];
}
For your problem of splitting insertion of a large array into chunks to be inserted to a DB via network operations, an NSOperationQueue can be created that will allow you to add a separate operation for each chunk of data to be inserted.
The queue can be set to run in a serial manner so that each operation will need to be complete before the next one is started.
Using a queue makes the multiple operations more manageable than having the flow be controlled by callbacks.
In summary, you create a queue and set its maximum concurrent operation count to 1. Then create an NSOperation subclass that performs the necessary steps to insert data into the database. Each chunk of data will correspond to a separate operation that will be added to the queue. Each operation will be performed in series until all are complete.
Here is an outline for the solution:
// Create a new queue to hold network operations.
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
// Split the large array into chunks of 20 items each.
NSInteger chunkSize = 20;
NSInteger i = 0;
NSInteger total = [lowMArray count];
while (i < total) {
NSInteger j = i;
NSMutableArray *chunk = [NSMutableArray alloc] init];
while (j < i + chunkSize - 1 && j < total) {
[chunk addObject:lowMArray[j]];
j++;
}
MyOperation *myOperation = [[MyOperation alloc] initWithArray:chunk];
self.operationQueue.addOperation(myOperation)
i += chunkSize;
}
MyOperation.h:
#interface MyOperation : NSOperation
- (instancetype)initWithArray:(NSArray *)chunk;
#property NSArray *chunk;
#end
MyOperation.m:
#implementation MyOperation
- (instancetype)initWithArray:(NSArray *)chunk
{
if (self = [super init]) {
self.chunk = chunk;
}
return self;
}
- (void)main
{
// Create Json data from lowMArray
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self.chunk
options:NSJSONWritingPrettyPrinted
error:nil];
// Construct post request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#/lows", _silServerBaseUrl]]];
request = [self applyAuth:request];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json; charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:jsonData];
// Send post request
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
// NSLog(#"Response Failed!");
} else {
// NSLog(#"Response Success!");
}
}];
[dataTask resume]; // runs task
}
#end
AFNetworking has support for its own NSOperation subclass in AFHTTPRequestOperation. An example can be found here. Also, the AFNetworking GitHub repository has an example for batch operations.
Based on your revised question, setting the completion block of each AFHTTPRequestOperation to handle the response and error can help to debug the problem.
Here is how it is done:
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) {
NSString* decodedResponse = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"response %#", decodedResponse);
} failure:^(AFHTTPRequestOperation * _Nonnull operation, NSError * _Nonnull error) {
NSLog(#"error %#", error);
}];
It would be inserted after AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];.
I have an app which downloads a set of photos from a server. I am using an Asynchronous request because I don't want the UI to be blocked. However, I am finding that the request is very slow and takes ages to load.
I know you can set the queue type to [NSOperationQueue mainQueue] but that just puts the Asynchronous request back on the main thread which defeats the whole point of making the request Asynchronously in the first place.
Is there anyway to speed up the request or to tell iOS: "Run this request in the background, but do it ASAP, don't leave it till the end of the queue"???
Here is my code:
// Set up the photo request.
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:PHOTO_URL, pass_venue_ID, PHOTO_CLIENT_ID, PHOTO_CLIENT_SECRET]];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// Begin the asynchromous image loading.
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error == nil) {
// Convert the response data to JSON.
NSError *my_error = nil;
NSDictionary *feed = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&my_error];
// Check to see if any images exist
// for this particular place.
int images_check = [[NSString stringWithFormat:#"%#", [[[feed objectForKey:#"response"] valueForKey:#"photos"] valueForKey:#"count"]] intValue];
if (images_check > 0) {
// Download all the image link properties.
images_prefix = [[[[feed objectForKey:#"response"] valueForKey:#"photos"] valueForKey:#"items"] valueForKey:#"prefix"];
images_suffix = [[[[feed objectForKey:#"response"] valueForKey:#"photos"] valueForKey:#"items"] valueForKey:#"suffix"];
images_width = [[[[feed objectForKey:#"response"] valueForKey:#"photos"] valueForKey:#"items"] valueForKey:#"width"];
images_height = [[[[feed objectForKey:#"response"] valueForKey:#"photos"] valueForKey:#"items"] valueForKey:#"height"];
// Set the image number label.
number_label.text = [NSString stringWithFormat:#"1/%lu", (unsigned long)[images_prefix count]];
// Download up to 5 images.
images_downloaded = [[NSMutableArray alloc] init];
// Set the download limit.
loop_max = 0;
if ([images_prefix count] > 5) {
loop_max = 5;
}
else {
loop_max = [images_prefix count];
}
for (NSUInteger loop = 0; loop < loop_max; loop++) {
// Create the image URL.
NSString *image_URL = [NSString stringWithFormat:#"%#%#x%#%#", images_prefix[loop], images_width[loop], images_height[loop], images_suffix[loop]];
// Download the image file.
NSData *image_data = [NSData dataWithContentsOfURL:[NSURL URLWithString:image_URL]];
// Store the image data in the array.
[images_downloaded addObject:image_data];
}
// Load the first image.
[self load_image:image_num];
}
else if (images_check <= 0) {
// error...
}
}
else {
// error
}
}];
Thanks for your time, Dan.
i think your problem isnt the request running slow, its that you are updating UI elements not on the main thread, surround any UI updates (like setting the text on labels) with
dispatch_sync(dispatch_get_main_queue(), ^{
<#code#>
});
As Fonix said its not iOS that responding slow but dataWithContentsOfURL doesn't work in background thread. Apple's recommendation is that you should use NSURLConnection asynchronously with delegates
- didReceiveResponse
- didReceiveData
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:_mAuthenticationTimeoutInterval];
In these methods you can make use of chunks of data as well.
If you actually want these multiple downloads to be faster you should use parallel downloading using NSOperationQueue. You can refer enter link description here
I think a good solution could be using AFNetworking when combined with NSOperation, check this code I wrote to do more than one operation asynchronously
NSMutableArray *operations = [[NSMutableArray alloc] init];
for(NSObject *obj in caches) {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
//...set up your mutable request options here
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"application/json"];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSInteger statusCode = operation.response.statusCode;
if(statusCode==200) {
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"API Call error:%#", error.localizedDescription);
}];
[[requestManager operationQueue] addOperation:operation];
[operations addObject:operation];
if([operations count] >= MAX_API_CALL) break;
}
[AFHTTPRequestOperation batchOfRequestOperations:operations progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
} completionBlock:^(NSArray *operations) {
NSError *error;
for (AFHTTPRequestOperation *op in operations) {
if (op.isCancelled){
}
if (op.responseObject){
// process your responce here
}
if (op.error){
error = op.error;
}
}
}];
In my iOS App,I have hundreds of image download.
I use AFNetworking to get those images.I want to manage the request number of AFWorking.
This is my code:
The problem is:It will block my UI.
THX for help me!
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(5);
for (NSString *urlString in self.downloadImageList) {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_async(group, queue, ^{
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSString *filename = url.lastPathComponent;
NSURL *outputFileURL = APPLICATION_DOCUMENTS_DIRECTORY;
outputFileURL = [outputFileURL URLByAppendingPathComponent:[NSString stringWithFormat:#"%#/images/%#",self.boardId,filename]];
dispatch_group_async(group, dispatch_get_main_queue(), ^{
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamWithURL:outputFileURL append:YES];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
[self.downloadImageList removeObject:urlString];
NIDINFO(#"download success %#",filename);
dispatch_semaphore_signal(semaphore);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NIDERROR(#"download image error:%#\n%#",error,urlString);
dispatch_semaphore_signal(semaphore);
}];
[operation start];
});
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(semaphore);
dispatch_release(group);
The problem is: It will block my UI.
Well yeah, that's sort of the point of dispatch_semaphore_t. If you remove those calls, your AFNetworking calls will execute asynchronously in the background without affecting your main / UI thread.
I don't know the full context of where this code is being used, but it looks like you may want to consider having the method that calls this take a block parameter, that can be called once all of the requests have finished. You may also want to take a look at AFHTTPClient's batch operations features, which allows you to track the progress of a group of operations, getting callbacks for each individually, and when all of then finish.
Here i am trying to call my ASIHTTPRequest in a GCD. Sometimes the comletion blocks and failed blocks are not executing. What i want to do is, after this request finished, i have to use the returned data in a another ASIHTTPRequest. So how to improve this code:
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]];
[request setCompletionBlock:^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
NSData *_responseData = [request responseData];
NSString *response = [[NSString alloc] initWithData:_responseData encoding:NSASCIIStringEncoding] ;
self.albumDic = [response JSONValue];
[response release];
dispatch_async(dispatch_get_main_queue(), ^{
[self GetDictionary:self.albumDic];
});
});
}];
[request setFailedBlock:^{
NSError *error = [request error];
NSLog(#"Error : %#", error.localizedDescription);
}];
[request startSynchronous];
Don't go that way. You're doing threading on threading (GCD uses threading and so does ASIHTTPRequest when used asynchronously).
Use ASINetworkQueue instead - read about it here
Here is a simple way you could use it:
- (void)addRequestsToNetworkQueue:(NSArray *)requests {
// Stop anything already in the queue before removing it
[[self networkQueue] cancelAllOperations];
// Creating a new queue each time we use it means we don't have to worry about clearing delegates or resetting progress tracking
[self setNetworkQueue:[ASINetworkQueue queue]];
[[self networkQueue] setDelegate:self];
[[self networkQueue] setRequestDidFinishSelector:#selector(requestFinished:)];
[[self networkQueue] setRequestDidFailSelector:#selector(requestFailed:)];
[[self networkQueue] setQueueDidFinishSelector:#selector(queueFinished:)];
//Add all requests to queue
for (ASIHTTPRequest *req in requests) {
[[self networkQueue] addOperation:req];
}
//Start queue
[[self networkQueue] go];
}
ASINetworkQueue provides many delegate methods (most are also customizable), so you can update the GUI when a request is finished and so forth. It is asynchronous, so GCD is unnecessary.