2011年1月14日金曜日

iOSアプリの動作をシミュレーターと実機で分岐する方法メモ

Cameramaticのカメラ周りの機能はUIImagePickerViewController を一切使用せず、AVFoundationフレームワークを利用しています。

AVFoundationを利用するとUIImagePickerViewControllerでは実現できないことまでカスタマイズが可能になります。
それはそれで大変素晴らしいのですが、一点だけ困ったことがありました。

AVFoundationはシミュレーターには対応していません。
(シミュレーター用にビルドするとエラーが発生する)

そのため、最初の頃は動作確認の際にいちいち実機に転送していました。
お察しの通りこれはすごく面倒です。

カメラ周りに関してはそういうものだと諦めていたのですが、カメラとは全然関係ない機能 (例えばFlickrに画像をアップロードする機能) の動作確認まですべて実機に転送しなければいけないというのは殺生です。


調べてみると解決策がありました。

シミュレータと実機で動作を分岐するには TARGET_IPHONE_SIMULATOR というマクロを使えば可能になっています。


#include "TargetConditionals.h"

#if TARGET_IPHONE_SIMULATOR
   // シミュレーター上でのみ実行される処理
#else
   // 実機でのみ実行される処理
#endif


TARGET_IPHONE_SIMULATORはTargetConditionals.hというファイルに定義されているので最初にincludeしておきます。


#if !TARGET_IPHONE_SIMULATOR

#import <AVFoundation/AVFoundation .h>

#endif
このように書くと実機でのみAVFoundationをimportします。
(もちろんここ以外にもAVFoudationを前提としている箇所にTARGET_IPHONE_SIMULATORで分岐処理を書く必要はあります。)

2011年1月5日水曜日

[iOS] バックグラウンドで処理を実行する方法メモ

iOS4.0になってiOSもマルチタスクに対応したので、iPhone上で複数のアプリを同時に起動できるようになりました。

...というのは古い話(といっても半年前ですか)で、iPhoneやiPadを使っている人にはいまや常識だと思いますが個人的に勘違いしていたことがあったのでメモしておきます。


マルチタスク対応といっても、バックグラウンドでなんでもかんでも実行できるわけではなく、ドキュメントにもあるとおり、バックグラウンドで処理を実行し続けることができるのは 音楽再生(audio)、位置情報取得(location)、VoIP この3種類だけです。


自作アプリにはこの3つの処理を行っているものがなかったので、「へえ」という感じで受け流してしまっていました。

だけど、よく考えたらFlickrの公式アプリはバックグラウンドでの画像のアップロードが可能になっています。

これはどういうことかともう一度ドキュメントを確認したところ、バックグラウンドで可能な処理として次の文がありました。

Task completion—applications can ask the system for extra time to complete a given task.

どうも、内容に関わらず特定のタスクが完了するまでシステムに一定の猶予の時間(最大10分程度)を与えてもらえるようです。

上にあげたaudio、location、voipが特別なのは、こちらは時間制限なく処理し続けることが可能である、と。



では、バックグラウンドで一定時間処理を実行させるためにはどうすればいいかというと、とても簡単です。

実行したいコードを UIApplication

beginBackgroundTaskWithExpirationHandler:
endBackgroundTask:

というメソッドでくるんであげるだけです。


たとえば画像のアップロードを行うとして
// UIBackgroundTaskIdentifier型の bgTask というプロパティが宣言されているとして

- (void)upload {
    UIApplication  *app = [UIApplication sharedApplication];

    // ここから「アプリがバックグラウンドに入っても実行し続けたい処理」が始まると通知
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        // このブロック内は一定時間内 (10分程度)に処理が完了しなかった場合に実行される。
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];

    // アップロード処理を適当に書く
    // アップロード中にアプリがバックグラウンドに入ってもアップロードは継続
}


// アップロード完了後に呼ばれるdelegateメソッド

- (void)uploadFinished {
    // 「アプリがバックグラウンドに入っても実行し続けたい処理」が終わったと通知
    [[UIApplication sharedApplication] endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
}