Как я могу узнать, когда очередь nsoperation завершила все запросы, чтобы я мог перезагрузить свой tableview?
Я загружаю данные из разных ссылок с помощью ASIHTTPRequest и NSOperationQueue в
Загрузка в фоновом режиме. Когда запрос завершен, я разбираю его с помощью requestFinished
Метод делегирования ASIHTTPRequest. Я хочу обновить данные в tableview, когда все запросы в
Очередь завершена. Есть ли способ узнать, когда NSOperationQueue обработал все
Запросы? я имею в виду, что очередь имеет любую переменную, такую как "isEmpty" или любой делегат метод типа "queueDidCompletedAllOperation"?
Пожалуйста, помогите.
Вот код:
//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's 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:((");
}
3 ответа:
Если все операции были завершены, то число массивов
operationsбудет равно нулю.Чтобы проверить это, вы можете использовать кодирование наблюдения значения ключа для наблюдения ключа
operationsNSOperationQueueУстановить наблюдателя для ключа
opertionsбудет следующим образом:[self.queue addObserver:self forKeyPath:@"operations" options:0 context:NULL];Затем сделайте это в своем observeValueForKeyPath, как показано ниже:
- (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]; } }После iOS 4.0 вы можете использовать свойство
operationCountКакself.queue.operationCount == 0вместо проверки, как это[self.queue.operations count] == 0
Я знаю, что на этот вопрос уже дан ответ, но для будущих читателей, если вы используете AFNetworking и, более конкретно, AFHTTPRequestOperation, Вы можете сделать что-то вроде этого:
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); }];Это для загрузчика, который добавляет загрузку в NSOperationQueue, а затем уведомляет два индикатора выполнения: 1 для прогресса файла и 1 для общего прогресса.
Надеюсь, это поможет
У меня есть пара вариантов:
Вместо этого используйте
ASINetworkQueueи установитеqueueDidFinishSelector, чтобы он сообщил вам, когда это будет сделано. Это также дает вам возможность не только обновлять представленияUIProgressViewне только для отдельных строк, но и для всего процесса загрузки.Не могли бы вы добавить что-то в свой
NSOperationQueue, что просто вызовет метод, чтобы затем обновить пользовательский интерфейс (в главной очереди, конечно)? Добавляя его в очередь, он не попадет в нее пока он не очистил очередь. Или в другой очереди вызовитеwaitUntilFinished, после чего можно обновить пользовательский интерфейс.Глядя на ваши комментарии, кажется, что вы обновляете свой пользовательский интерфейс в
requestFinished, но недовольны, потому что вы думаете, что было бы лучше подождать, пока все обновления состоятся. Лично я предпочитаю обновлять пользовательский интерфейс, запрос за запросом, таким образом, если он медленный, вы получаете промежуточную обратную связь, а не ждете всего. Это должно быть сделано изящно, но мне нравится обновление пользовательского интерфейса, как я иду вперед. Следует признать, что некоторые процессы не поддаются этому.В этом последнем пункте я думаю, что фокус в том, чтобы сделать эти обновления, чтобы они не отвлекали. В частности, если ваш пользовательский интерфейс является
UITableView, вы, вероятно, не хотите сделатьtableView.reloadData, который перезагрузит всю таблицу. Вместо этого вы, вероятно, захотите проверить, загружена ли ячейка (черезcellForRowAtIndexPath, методUITableView, Не путать с методомUITableViewControllertableView:cellForRowAtIndexPath), и если да, обновить эта одна строка, например: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]; }