Как я могу узнать, когда очередь 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 4

3 ответа:

Если все операции были завершены, то число массивов operations будет равно нулю.

Чтобы проверить это, вы можете использовать кодирование наблюдения значения ключа для наблюдения ключа operations NSOperationQueue

Установить наблюдателя для ключа 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 для общего прогресса.

Надеюсь, это поможет

У меня есть пара вариантов:

  1. Вместо этого используйте ASINetworkQueue и установите queueDidFinishSelector, чтобы он сообщил вам, когда это будет сделано. Это также дает вам возможность не только обновлять представления UIProgressView не только для отдельных строк, но и для всего процесса загрузки.

  2. Не могли бы вы добавить что-то в свой NSOperationQueue, что просто вызовет метод, чтобы затем обновить пользовательский интерфейс (в главной очереди, конечно)? Добавляя его в очередь, он не попадет в нее пока он не очистил очередь. Или в другой очереди вызовите waitUntilFinished, после чего можно обновить пользовательский интерфейс.

  3. Глядя на ваши комментарии, кажется, что вы обновляете свой пользовательский интерфейс в requestFinished, но недовольны, потому что вы думаете, что было бы лучше подождать, пока все обновления состоятся. Лично я предпочитаю обновлять пользовательский интерфейс, запрос за запросом, таким образом, если он медленный, вы получаете промежуточную обратную связь, а не ждете всего. Это должно быть сделано изящно, но мне нравится обновление пользовательского интерфейса, как я иду вперед. Следует признать, что некоторые процессы не поддаются этому.

В этом последнем пункте я думаю, что фокус в том, чтобы сделать эти обновления, чтобы они не отвлекали. В частности, если ваш пользовательский интерфейс является UITableView, вы, вероятно, не хотите сделатьtableView.reloadData, который перезагрузит всю таблицу. Вместо этого вы, вероятно, захотите проверить, загружена ли ячейка (через cellForRowAtIndexPath, метод UITableView, Не путать с методом UITableViewController tableView: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];
}