Apple docsを見ると、次のように書かれています。
待つ
指定されたセレクターがメイン スレッドのレシーバーで実行されるまで、現在のスレッドをブロックするかどうかを指定するブール値。このスレッドをブロックするには YES を指定します。それ以外の場合は、NO を指定して、このメソッドがすぐに戻るようにします。現在のスレッドがメイン スレッドでもあり、このパラメーターに YES を指定すると、メッセージはすぐに配信されて処理されます。
したがって、このメソッドをメイン スレッドから呼び出すと、すぐに実行されます。
でも、そんなことをしても全く意味がありません。メイン スレッドを使用していて、メイン スレッドで実行したい場合はgetBooks
、次のようにします。
-(void) viewDidLoad {
[super viewDidLoad];
[self getBooks];
}
の中で実際に何をしているかを見せていただければgetBooks
、さらにお役に立てるかもしれません。たとえば、getBooks
オンラインの本のデータを取得するために、リモート HTTP リクエストを作成している場合は、まったく使用したくありませんperformSelectorOnMainThread:
。これをバックグラウンド スレッドで実行し、ネットワーク リクエストが完了したら、メイン スレッドをコールバックして UI を更新するだけです。
アップデート:
Web コンテンツを取得するには、さまざまな方法があります。そのまま直接使用するNSURLRequest
場合は、このクラスがNSURLConnectionDelegate
プロトコルを実装していることを確認する必要があります。
@interface MyViewController: UIViewController<NSURLConnectionDelegate> {
Appleの例に従ってそのメソッドを実装します
- (void) connection:(NSURLConnection *) connection didReceiveResponse:(NSURLResponse *) response
{
// this method is called when the server has determined that it
// has enough information to create the NSURLResponse
// it can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
[receivedData setLength:0];
}
- (void) connection:(NSURLConnection *) connection didReceiveData:(NSData *)data
{
// append the new data to the receivedData
[receivedData appendData:data];
}
- (void) connection:(NSURLConnection *) connection didFailWithError:(NSError *) error
{
// release the connection, and the data object
[connection release];
[receivedData release];
// inform the user
UIAlertView* netAlert = [[UIAlertView alloc] initWithTitle:@"" message:@"Oops!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[netAlert show];
[netAlert release];
}
- (void) connectionDidFinishLoading:(NSURLConnection *) connection
{
if ([receivedData length] > 0) {
// do something with the data, and then tell the UI to update
[self performSelectorOnMainThread: @selector(updateUI) withObject: nil waitUntilDone: NO];
}
// release the connection, and the data object
[connection release];
[receivedData release];
receivedData = nil;
}
-(void) updateUI {
[tableView reloadData];
someLabel.text = @"New Status";
// whatever else needs updating
}
注: 上記のコードは、ARC が導入される前に作成されました。プロジェクトで ARC を使用している場合は、これらのすべての行をrelease
呼び出しで削除する必要があります。receivedData
ただし、複数の呼び出しで使用するため、 が適切に保持されていることを確認することをお勧めします。
別の注意:NSURLConnection
複数の方法で使用できます。同期または非同期で使用できます。また、開始するスレッドをいつでも決定できます。これを保持する場合:
-(void) viewDidLoad {
[super viewDidLoad];
[self getBooks];
}
その後、メインスレッドで接続が開始されます。ただし、それでも非同期操作になります。viewDidLoad
つまり、ネットワーク リクエストが完了するまでブロックされません。ただし、ダウンロード中にユーザーが UI で重要なこと (スクロールなど) を行う場合、UI の応答性が低下することがあります。その場合は、これを実行するか、ネットワーク操作をバックグラウンド スレッドに強制することができます。これを行うには、次から始めます。
-(void) viewDidLoad {
[super viewDidLoad];
[self performSelectorInBackground: @selector(getBooksInBackground) withObject: nil];
}
次に、上記のNSURLConnectionDelegate
コードの唯一の問題は、バックグラウンド スレッドがデリゲート コールバックを介して応答を配信するのに十分な長さではないことです。それを生かし続けるために、
-(void) getBooksInBackground {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[self getBooks];
CFRunLoopRun(); // Avoid thread exiting
[pool release];
}
そして、この呼び出しを両方の最後に追加し、このバックグラウンド実行ループをクリーンアップする必要がありconnectionDidFinishLoading
ますconnection:didFailWithError
。
CFRunLoopStop(CFRunLoopGetCurrent());
繰り返しますが、古いコードなので、使用してください
@autoreleasepool {
}
アーク用。