How can I find out when the nsoperation queue completed all the requests so that I can reload my tableview?

I load data from different links using ASIHTTPRequest and NSOperationQueue in

Download in the background. When the request is complete, I understand using requestFinished

delegate the ASIHTTPRequest method. I want to update data in tableview when all requests in

the queue is complete. Is there any way to find out when NSOperationQueue processed everything

inquiries? I mean, is there a variable in the queue like 'isEmpty' or any delegate method like 'queueDidCompletedAllOperation'?

Please, help.

Here is the code:

//source @interface SourceModel : NSObject @property (nonatomic, retain) NSString * link; @property (nonatomic, retain) NSString * name; @end //for rssGroup @interface CompleteRSSDataModel : NSObject @property (nonatomic,strong) SourceModel * source; @property (nonatomic,strong) KissXMLParser * parser; @property (nonatomic,strong) NSArray * rssArticles; @end - (void)viewDidLoad { for (int index=0; index<[rssGroups count]; index++) { NSString * urlString = [[[rssGroups objectAtIndex:index] source] link]; NSURL *url = [NSURL URLWithString:urlString]; ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; [request setDelegate:self]; //set this request tag to group index of this source(link). See requestFinished for use of this :) [request setTag:index]; [self.queue addOperation:request]; } } - (void)requestFinished:(ASIHTTPRequest *)request { NSLog(@"%@",@"RSS Data got from internet successfully :))"); int groupIndex = [request tag]; CompleteRSSDataModel * group = [rssGroups objectAtIndex:groupIndex]; group.parser = [[KissXMLParser alloc]initWithData:[request responseData]]; if (group.parser == nil) { NSLog(@"%@",@"Failed - Error in parsing data :(("); } else { NSLog(@"%@",@"Data Parsed successfully :))"); group.rssArticles = [group.parser itemsInRss]; //So i want to check here that queue is empty, reload data, but as my information, i don't know any method like hasCompletedAllRequested //if(self.queue hasCompletedAllRequests) { // [self.tableview reloadData]; //} } } - (void)requestFailed:(ASIHTTPRequest *)request { NSLog(@"%@",@"Error in Getting RSS Data from internet:(("); } 
+4
source share
3 answers

If all operations are completed, then the calculation of the operations array will be zero.

To verify this, you can use Key Value Observation Encoding to observe the NSOperationQueue operations NSOperationQueue

To set an observer for the opertions key, it will look like this:

 [self.queue addObserver:self forKeyPath:@"operations" options:0 context:NULL]; 

Then do this in your watchValueForKeyPath, as shown below:

 - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == self.queue && [keyPath isEqualToString:@"operations"]) { if ([self.queue.operations count] == 0) { // Do something here when all operations has completed NSLog(@"queue has completed"); } } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } 

After iOS 4.0, you can use the operationCount property as self.queue.operationCount == 0 instead of checking it as [self.queue.operations count] == 0

+10
source

I know this has already been answered, but for future readers, if you use AFNetworking and, more specifically, AFHTTPRequestOperation , you can do something like this:

 NSString *urlPath = [NSString stringWithFormat:@"%@%@", baseUrl, file]; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlPath]]; AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; [operation setCompletionBlockWithSuccess: ^(AFHTTPRequestOperation *operation, id responseObject) { if ([[queue operations] count] ==0) { NSNotification * success = [NSNotification notificationWithName:@"TotalDone" object:[NSNumber numberWithBool: YES]]; [[NSNotificationCenter defaultCenter] postNotification:success]; queueSize = 0; } else { //get total queue size by the first success and add 1 back if (queueSize ==0) { queueSize = [[queue operations] count] +1.0; } float progress = (float)(queueSize-[[queue operations] count])/queueSize; NSNumber * totProgress = [NSNumber numberWithFloat:progress]; NSNotification * totalProgressNotification = [NSNotification notificationWithName:@"TotalProgress" object:totProgress]; [[NSNotificationCenter defaultCenter] postNotification:totalProgressNotification]; } } failure:^(AFHTTPRequestOperation *operation, NSError *error) NSLog(@"Error: %@", error); }]; 

This is for the bootloader, which adds the load to NSOperationQueue, then notifies two progress indicators: 1 for file progress and 1 for overall progress.

Hope this helps

+2
source

Several options jump on me:

  • Instead, use ASINetworkQueue and set the queueDidFinishSelector so that it tells you when it will be done. It also gives you the ability to not only update UIProgressView not only for individual rows, but for the entire loading process.

  • Could you add something to your NSOperationQueue that just calls the method to update your user interface (in the main queue, of course)? By adding it to the queue, it will not reach it until it clears the queue. Or in another queue call waitUntilFinished , after which you can update your interface.

  • Looking at your comments, it looks like you are updating your user interface in requestFinished , but you’re not happy because you think it would be better to wait until all the updates take place. Personally, I prefer to update the user interface, request on demand, so if it is slow, you get intermediate feedback, rather than expecting everything. It needs to be done gracefully, but I like to update the interface when I go. Admittedly, some processes are not amenable to this.

In this last paragraph, I think the trick is to make these updates so that it does not distract. In particular, if your user interface is a UITableView , you probably won't want to make tableView.reloadData , which will reload the entire table. Instead, you probably want to check if the cell is loaded (via cellForRowAtIndexPath , the UITableView method so as not to be confused with the UITableViewController tableView:cellForRowAtIndexPath )), and if so, update this line, for example:

 NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section]; UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath]; if (cell) { // you can either update the controls in the cell directly, or alternatively, just // call reloadRowsAtIndexPaths to have the tableView use your data source: [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; } 
0
source

All Articles