NSBlockOperation
NSBlockOperation Class Reference
NSBlockOperation は従来 -[NSOperation main] に実装していた処理を Blocksで書くことができる。こんな感じ。
NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock: ^{
// 処理1
}];NSOperation のサブクラスなので実行開始は start を投げてやればよい。
[operation start];複数の処理を走らせたい時は addExecutionBlock: で処理 Blocksを追加していく。
[operation addExecutionBlock:^{
// 処理2
}];終了時に処理を実行したい場合は iOS4 から NSOperation に追加された setCompletionBlock: で処理を指定しておくことができる。NSOperation Class Reference - setCompletionBlock:
[operation setCompletionBlock:^{
// 終了時処理
}];なお start で実行した後は、すべての処理が完了するまでその場でブロックされる。サンプル
NSBlockOperation を使ったサンプルプログラムを作って動きを確かめてみた。
実行すると2つの処理が同時に走る。thread1は1秒間隔でラベルを更新していく。thread2の方は2秒間隔で更新する。
ソースコードはこんな感じ。
- (IBAction)start:(id)sender
{
NSLog(@"setup");
NSLog(@"1: %@", [NSThread currentThread]);
NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock: ^{
NSLog(@"2: %@", [NSThread currentThread]);
for (int i=0; i < 10; i++) {
[label performSelectorInBackground:@selector(setText:)
withObject:[NSString stringWithFormat:@"running: %d", i+1]];
[NSThread sleepForTimeInterval:1.0];
}
}];
[operation addExecutionBlock:^{
NSLog(@"3: %@", [NSThread currentThread]);
for (int i=0; i < 5; i++) {
[label2 performSelectorInBackground:@selector(setText:)
withObject:[NSString stringWithFormat:@"running: %d", i+1]];
[NSThread sleepForTimeInterval:2.0];
}
}];
[operation setCompletionBlock:^{
NSLog(@"completion");
label.text = @"completion";
label2.text = @"completion";
}];
NSLog(@"start");
[operation start];
NSLog(@"end");
}UILabelの更新はメインスレッドで行う必要があるため -[NSObject performSelectorInBackground:withObject:] を使っている。動作中のコンソール:
setup
1: <NSThread: 0x590db20>{name = (null), num = 1}
start
2: <NSThread: 0x590db20>{name = (null), num = 1}
3: <NSThread: 0x5d36840>{name = (null), num = 3}
end
4: <NSThread: 0x5d36840>{name = (null), num = 3}これを見ると次のことがわかる。
- 1番目の処理はメインスレッドで走っている(NSThreadが同じ)
- すべての処理が完了するまでブロックされる
- completion処理はブロック解除後に非メインスレッドで実行される
最後の動作が腑に落ちない感じもするがそういうものなのだろう。
ソースは GitHub からどうぞ。
WaitScreenSample at 2010-09-05 from xcatsan's iOS-Sample-Code - GitHub
実機での動作
ここまでは iPhone シミュレータでの話。
実機で走らせるとまた違った動作になった。
setup
1: <NSThread: 0x105210>{name = (null), num = 1}
start
2: <NSThread: 0x105210>{name = (null), num = 1}
3: <NSThread: 0x105210>{name = (null), num = 1}
end
4: <NSThread: 0x151820>{name = (null), num = 18}メインスレッドだけで処理が走っている?実際画面上の動作を見ても thread1 のカウントアップが終了した後、thread2のカウントアップが走る。同時には動作しない。
うーむなぜだろう。書き方が悪いのか?
...今日は時間切れ。
参考情報
- Concurrency Programming Guide: Operation Queues (日本語訳) - steelwheelsの日記
- Concurrency Programming Guide: Introduction
- Using Concurrency To Improve Responsiveness
- Togetter - 「【技術情報】iOS 4のNSOperationはGCD使用か否かの俺様用まとめ」




Responses
Leave a Response