これを実現するために、Grand Central Dispatch (GCD) メソッドを使用しました。これは、単純なテストアプリで私のために働いた例です (静的ライブラリに適用されるかどうかはわかりませんが、一見の価値があるかもしれません)。ARCを使用しています。
この例では、viewDidLoad メソッドからいくつかのバックグラウンド作業を開始していますが、どこからでも開始できます。重要なのは、「dispatch_async(dispatch_get_global_queue…」がバックグラウンド スレッドでブロックを実行することです。その方法の適切な説明については、この回答を参照してください。
これが私のviewDidLoadです:
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL),
^(void) {
[self doStuffInBackground];
});
}
この時点で doStuffInBackground メソッドはバックグラウンドで実行されているため、NSURLConnection を同期的に使用できます。ここでの私の例では、おそらく他のコードが backgroundStuffShouldRun = false を設定するまで、メソッドはネットワーク呼び出しをループします。ネットワーク呼び出しは、10 秒のタイムアウトで行われます。通話の後、進行状況を表示するためだけに UI ラベルを更新しています。UI の更新は "dispatch_async(dispatch_get_main_queue()…") で実行されることに注意してください。これにより、必要に応じて UI スレッドで UI の更新が実行されます。
このバックグラウンド作業の 1 つの潜在的な問題: http 要求自体をキャンセルする方法がありません。ただし、タイムアウトが 10 秒の場合、部外者 (おそらく UI の何らかのイベント) が backgroundStuffShouldRun = false を設定した後、スレッドがそれ自体を中止するまで最大 10 秒待機することになります。
- (void)doStuffInBackground
{
while (backgroundStuffShouldRun) {
// prepare for network call...
NSURL* url = [[NSURL alloc] initWithString:@"http://maps.google.com/maps/geo"];
// set a 10 second timeout on the request
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLCacheStorageAllowed timeoutInterval:10];
NSError* error = nil;
NSURLResponse *response = nil;
// make the request
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// were we asked to stop the background processing?
if (!backgroundStuffShouldRun) {
return;
}
// process response...
NSString* status = @"Success";
if (error) {
if (error.code == NSURLErrorTimedOut) {
// handle timeout...
status = @"Timed out";
}
else {
// handle other errors...
status = @"Other error";
}
}
else {
// success, handle the response body
NSString *dataAsString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", dataAsString);
}
// update the UI with our status
dispatch_async(dispatch_get_main_queue(), ^{
[statusLabel setText:[NSString stringWithFormat:@"completed network call %d, status = %@", callCount, status]];
});
callCount++;
sleep(1); // 1 second breather. not necessary, but good idea for testing
}
}