つの要求が実際に(ここではそうではありません)が発行される前に、前の要求の結果を必要としない限り、あなたはが順番に実行すべきではありません。連続して発行する方がより論理的だと感じるかもしれませんが、そうするには大きなパフォーマンス上のペナルティがあります。それらを同時に発行し、結果をいくつかの順序付けられていない構造(辞書のようなもの)に保存して、すべて完了したら順序構造を構築します。
NSMutableDictionary *results = [NSMutableDictionary dictionaryWithCapacity:[paths count]];
// don't create new session for each request ... initialize this outside of the loop
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; // or since you're not doing anything special here, use `sharedSession`
// since we're going to block a thread in the process of controlling the degree of
// concurrency, let's do this on a background queue; we're still blocking
// a GCD worker thread as these run (which isn't ideal), but we're only using
// one worker thread.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// only do for requests at a time, so create queue a semaphore with set count
dispatch_semaphore_t semaphore = dispatch_semaphore_create(4); // only do four requests at a time
// let's keep track of when they're all done
dispatch_group_t group = dispatch_group_create();
// now let's loop through issuing the requests
for (NSString *path in paths) {
dispatch_group_enter(group); // tell the group that we're starting another request
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // wait for one of the four slots to open up
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:path]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
// ...
} else {
NSError *parsingError = nil;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (parsingError) {
} else {
// synchronize updating of dictionary
dispatch_async(dispatch_get_main_queue(), ^{
results[path] = dict;
});
}
}
dispatch_semaphore_signal(semaphore); // when done, flag task as complete so one of the waiting ones can start
dispatch_group_leave(group); // tell the group that we're done
}];
[task resume];
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// trigger whatever you want when they're all done
// and if you want them in order, iterate through the paths and pull out the appropriate result in order
for (NSString *path in paths) {
// do something with `results[path]`
}
});
});
ここで余分な依存関係の量を減らそうとしたので、ディスパッチグループとセマフォを使用しました。上記では、セマフォーを使用して並行性の程度を制限し、ディスパッチグループを使用して、いつ完了したかを識別します。
私はセマフォとグループを使用しませんが、これらの要求を非同期のNSOperation
サブクラスでラップしますが、私は自分のコードに加えた変更を制限しようとしていました。しかし、NSOperation
アイデアは論理的には上記と同じです:同時に実行しますが、同時実行の度合いを制限してタイムアウトにならないようにし、すべての結果が取得されたときだけ結果の取得をトリガーします。
出典
2016-06-28 22:27:23
Rob
「NSOperationQueue」アプローチの手順については、http://stackoverflow.com/a/23837970/1271826またはhttp://stackoverflow.com/a/24943851/1271826を参照してください。 – Rob
ありがとう@ロブ、私はセマフォを使用しようとしましたが、それは私のために働いていませんでした。もちろん、私は順番にそれをやろうとしていた...これは、私がそれらを発行した順序で記述したかったからです。私はあなたが提案したように後でそれらを注文することができます。 NSOpertionを試してみるかもしれません。 –
セマフォは、正しく使用されないと問題(特にデッドロック)を引き起こす可能性があります。私は非同期 'NSOperation'のアプローチははるかにエレガントだと思うが、上記はうまくいくはずです。 – Rob