が存在するだけで、それが非同期メソッドcompletionHandler
であると論理的に推測される可能性があります。setGroupWithName
これは iOS 開発における一般的なプログラミング パターンです。時間のかかるプロセスをフォアグラウンドで実行するのではなく (その間にユーザー インターフェイスがフリーズします)、バックグラウンドで非同期に実行しますが、この場合はブロックを渡しますcompletionHandler
。非同期プロセスが完了したときに何が起こるべきかを特定できます。
この場合、バックグラウンド スレッド/キューで を呼び出しているように見えますが、それがsetGroupWithName
起こっている間はメイン スレッド (この場合はそのNSLog
ステートメント) を続行し、アプリの応答性を維持することを理解しています。その遅い操作が完了している間。しかし、その非同期バックグラウンド操作setGroupWithName
が完了すると、 によって表されるコードのブロックが実行さcompletionHandler
れます (この場合、s
toの設定@"something"
)。
に設定しているブロックNSLog
内にステートメントを配置すると、 の呼び出し後にある既存のステートメントのかなり後にそれが発生していることがわかります。completionHandler
s
@"something"
NSLog
setGroupWithName
completionHandler
例を説明するために、パラメータを持つ標準的な Cocoa メソッド、つまりNSURLConnection
クラス メソッドの例を次に示しますsendAsynchronousRequest
。
問題は、遅い操作を実行する方法ですが、遅いインターネット操作を待たずに応答性の高いユーザー インターフェイスを維持する方法です。
したがって、次のコードを検討してください。
- (void)performSearch:(NSString *)term
{
NSLog(@"%s start: array has %d items", __FUNCTION__, [self.array count]);
// prepare to do search (the details here are not relevant)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://search.twitter.com/search.json?q=%@", term]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// submit an Internet search that will be performed in the background
[NSURLConnection sendAsynchronousRequest:request
queue:queue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// in the background, when the Twitter search is done,
// and when it's done, we'll make an array of the results
self.array = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"%s: after background query, array now has %d items", __FUNCTION__, [self.array count]);
}];
// in the meantime, let's immediately carry on while that search is taking place
NSLog(@"%s end: array still has %d items", __FUNCTION__, [self.array count]);
}
このコードの詳細はそれほど重要ではありませんが、基本的な考え方は、何か遅いこと (インターネットで Twitter 検索を実行すること) を行っているということですが、すぐにメイン スレッドでコードを実行し続け、バックグラウンド スレッドを独自のペース。
NSLog
さまざまなステートメントのタイムスタンプは、これらすべてのタイミングを示しています。
2013-05-02 20:42:58.922 myapp[81642:c07] -[ViewController performSearch:] 開始: 配列に 0 項目があります
2013-05-02 20:42:58.923 myapp[81642:c07] -[ViewController performSearch:] end: 配列にはまだ 0 個の項目があります
2013-05-02 20:42:59.798 myapp[81642:1303] __32-[ViewController performSearch:]_block_invoke: バックグラウンド クエリの後、配列には 11 項目が含まれるようになりました
「開始」から「終了」までの経過時間は約 1 ミリ秒ですが、バックグラウンドでの Twitter 検索の完了にはほぼ 1 秒かかりました。設計原則は、これを非同期で行わなかったcompletionHandler
場合 (この場合は を使用)、アプリのユーザー インターフェイスがその 1 秒間フリーズするというものです。しかし、非同期プログラミング手法を使用することで、アプリは良好で応答性に優れたままになりましたが、バックグラウンドで低速な操作が実行されました。
私はあなたのsetGroupWithName
方法に精通していませんが、おそらく同じ種類の非同期操作を実行しています。したがって、直後に値を見ようとする試みは、そのメソッドが完了すると変更される値を反映しません (私の例の「終了」NSLog ステートメントが、発生する変更を反映していないという事実のようなものです。 2 番目以降)。