4

ASIHTTPRequest と NSOperationQueue を使用して、さまざまなリンクからデータをダウンロードしています

バックグラウンド スレッドでダウンロードします。リクエストが終了したら、requestFinished を使用して解析します

ASIHTTPRequest のデリゲート メソッド。すべてのリクエストが入ったときにテーブルビューのデータを更新したい

キューが完了しました。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:((");

}
4

3 に答える 3

10

すべての操作が完了すると、operations配列カウントはゼロになります。

これを確認するには、Key Value Observation Coding を使用して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

于 2012-08-11T05:27:17.480 に答える
2

これはすでに回答されていることは知っていますが、将来の読者のために、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 に追加し、2 つのプログレス バーを通知するダウンローダ用です。1 つはファイルの進行状況、もう 1 つは全体の進行状況です。

お役に立てれば

于 2013-02-20T01:15:35.317 に答える
0

いくつかのオプションが私に飛び出します:

  1. ASINetworkQueue代わりに使用し、を設定するqueueDidFinishSelectorと、完了したときに通知されます。UIProgressViewこれにより、個々の行だけでなく、ダウンロードプロセス全体の別の行のビューも更新する機会が得られます。

  2. NSOperationQueueメソッドを呼び出してUIを更新するだけの何かを追加できますか(もちろん、メインキューで)?それをキューに追加することにより、キューをクリアするまでそのキューに到達しません。または、別のキューで、を呼び出しwaitUntilFinishedます。その時点で、UIを更新できます。

  3. コメントを見ると、でUIを更新しているように見えますがrequestFinished、すべての更新が行われるのを待つ方がよいと思われるため、不満があります。個人的には、UIを更新して、リクエストごとに更新することを好みます。そうすれば、遅い場合は、すべてを待つのではなく、暫定的なフィードバックを受け取ることができます。これは適切に行う必要がありますが、UIを更新するのが好きです。確かに、一部のプロセスはそれに適していません。

この最後の点で、私はそれが気を散らさないようにこれらの更新を行うことがトリックだと思います。具体的には、UIがである場合、テーブル全体をリロードする、を実行したくないUITableView可能性があります。代わりに、セルがまだロードされているかどうかを確認し(メソッドを介して、メソッドと混同しないように)、ロードされている場合は、その1つの行を更新します(例:tableView.reloadDatacellForRowAtIndexPathUITableViewUITableViewControllertableView: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];
}
于 2012-08-11T05:13:01.453 に答える