なにか非同期のリクエストを送るメソッド呼び出しを行う場合、よくあるデザインとして、
完了をblocksで通知してくれるものがあります。
例えば、
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://google.co.jp"]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
}];
のようなケースです。
シングルリクエストならこれでいいでしょう。
しかしながら、これをループさせたくなったとき、多くの人ははたと手が止まってしまうのではないでしょうか?
というのも、
for(int i = 0 ; i < 10 ; ++i)
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://google.co.jp"]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
}];
}
というのは良くないことが目に見えているからです。
できれば1つずつ完了を待ってやりたいですね。
そこで登場するのが今回の肝、再帰呼び出し(線形反復)です。
- (void)downloadWithURLs:(NSArray *)urls iteration:(int)i
{
if(urls.count <= i)
{
//done.
NSLog(@"all done.");
return;
}
NSLog(@"downloading...");
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urls[i]]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSLog(@"downloading done.");
[self downloadWithURLs:urls iteration:i + 1];
}];
}
//呼び出し側
NSArray *urls = @[@"http://google.co.jp", @"http://google.co.jp", @"http://google.co.jp"];
[self downloadWithURLs:urls iteration:0];
これを実行すれば、以下の出力を得られます
2013-02-08 16:49:00.808 MultipleDownloadIdiom[11178:c07] downloading...
2013-02-08 16:49:00.942 MultipleDownloadIdiom[11178:c07] downloading done.
2013-02-08 16:49:00.942 MultipleDownloadIdiom[11178:c07] downloading...
2013-02-08 16:49:01.001 MultipleDownloadIdiom[11178:c07] downloading done.
2013-02-08 16:49:01.002 MultipleDownloadIdiom[11178:c07] downloading...
2013-02-08 16:49:01.082 MultipleDownloadIdiom[11178:c07] downloading done.
2013-02-08 16:49:01.083 MultipleDownloadIdiom[11178:c07] all done.
ちゃんとやりたいことが実現できています
少々アクロバティックではありますが、目的が達成できました。