ここ暫く、常駐でiPhoneアプリの開発をしてきました。他人のアプリ開発をすると、想定外の機能や仕様を実装することになることがしばしばです。そうすると、知らなかったやり方を調べたり考案したりしなくてはならず、勉強になることも多いです。この過程で分った、iOS開発のtipsを紹介して行きます。
iOSアプリのスレッドの扱い
iOSの開発では、通常はスレッドを意識する必要はありません。基本的には、システムから呼ばれる(例えばViewController Class等の)メソッドを実装するわけですが、これらは、殆どMainThreadで動きます。また、非同期APIなどでは、システムが適宜スレッドを分けて実行してくれるからです。しかし、UIActionIndicaterを使うときなどで、例えばUIWebViewのデリゲートが別スレッドから呼ばれるのに気づいたります。
新たに別スレッドを上げて、非同期に実行する
iOSでは、コールバックとして呼ばれたメインスレッドを止めてしまうことはできませんので、重い処理や、待ちを入れないとならない処理は、別スレッドで実行する必要があります。これは、以下のように、doInTheOtherThreadメソッドを作成して呼出します。このとき、別スレッドのメソッドは、メモリプールを別に取らないとならないようで
[self performSelectorInBackground:@selector(doInTheOtherThread) withObject:paramObj];
......;
(void)
doInTheOtherThread:(id)paramObj {
NSAutoreleasePool *pool= [[NSAutoreleasePool alloc] init];
if (pool == nil) return;
.....;
[pool drain];
}
別スレッドから、メインスレッドとして実行する
処理は別スレッドで行った場合で、一部の処理をメインスレッドで実行したい場合です。特に、UIメッセージはメインスレッドから発行しないとなりませんので、この目的で頻繁に使います。この場合は、当該処理をメソッドに分けて、メインスレッドのコンテキストで実行します。
[NSObject performSelectorOnMainThread:doInTheMainThread withObject:paramObj waitUntilDone:YES];
メインスレッドで一時的に待ちを入れる
メインスレッドはメソッド内部で待ちに入ることはできない(再開できなくなります)のですが、RunLoopに戻って実行を遅延させることはできます。これは、例えばUIActionIndicatorの表示をする際に使うことができます。(これを使わない限り、startAnimationとstopAnimationを一つの関数の中で実行しても、表示されません)
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.0f]];
非メインスレッドで同期する
メインスレッドでなければ、mutexで待合わせることは可能です。例えば、以下のようなコードになります。この場合は、2回目のlockでウェイトします。
MethodRunOnThread1 {
pthread_mutex_init(&mutex, &attr);
pthread_mutex_lock(&mutex);
[self performSelectorInBackground:@selector(
MethodRunOnThread2) withObject:nil];
pthread_mutex_lock(&mutex);
phtread_mutex_unlock(&mutex);
do_next_things...;
}
MethodRunOnThread2 {
do something;
phread_mutex_unlock(&mutex);
}