UIKitにインジケーターを表現する"UIActivityIndicatorView"があるので、「このViewを表示してあげるだけでいーのね」と思ったら、とんでもない。以下を考慮した実装が必要です。
- Viewの実装
- 別スレッドで処理
- コールバック
- リリースタイミング
Viewの実装
まずは UIActivityIndicatorView を生成します。これは当然ですね。UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhite; [indicator setCenter:CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2)];
別スレッドで処理
インジケーターを表示したいってことは、当何らかの処理をさせたい訳なんですが、同一スレッド上でインジケーター生成 → インジケーターViewを追加 → やりたい処理 → インジケーターView削除ではダメなんです。
インジケーターViewを追加した状態でViewControllerの処理をいったん抜けて、端末上で描画処理まで進めてあげなければいけません。だから別スレッドで「やりたい処理」を実行させないとダメなんです。
そこで、メソッド"performSelectorInBackground"で別スレッドを立てて、引数のselectorで「やりたい処理」を呼び出してあげます。
// インジケーターView追加 [self.navigationController.view addSubview:self.indicator]; // インジケーター再生 [self.indicator startAnimating]; // 別スレッドで処理 [self performSelectorInBackground:@selector(othreProcess) withObject:nil]; [self.window makeKeyAndVisible];
コールバック
続いて、別スレッドでの「やりたい処理」が終わったら、メインスレッドへ処理が終わった旨を通知(コールバック)し、インジケーターの表示を止めてあげます。ここでは"hideIndicator"というメソッドを呼び出しています。また、別スレッドを立てる場合は新たなスレッドでのautoreleaseを格納する"NSAutoreleasePool"を宣言してあげる必要があるようです。
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // // ここでやりたい処理を実行。 // [pool release]; // 終了処理をメインスレッドへ通知 [self performSelectorOnMainThread:@selector(hideIndicator) withObject:nil waitUntilDone:NO];
-(void)hideIndicator { [self.indicator removeFromSuperview]; [self.indicator stopAnimating]; }
リリースタイミング
最後に、別スレッドで実行した「やりたい処理」で、何らかのインスタンスを生成する場合、慣習的に "autorelease" を明示していると、先ほどの"NSAutoreleasePool"のreleaseメソッドを呼んだタイミングで開放されてしまいます。ですので、autorelease とせずに、適切なタイミングを考慮して "release" を呼んであげる必要があります。
なんかインジケーターってよく見るので、もっと簡単、簡潔に実装できるもんだと思っていましたが、結構手間ですね。UIKit ってやつは。。。