BAD_ACCESS

おもにiOS、ときどき変な電子工作、ガジェット話。

AVCaptureSessionを使ってカメラアプリをつくるときのUI関連処理

カメラアプリ実装での悩み。開発継続中。

iOS4から利用可能となっているAVCaptureSessionを使うことでカメラアプリの自由度が格段に上がる!
ということでドキュメント精読。

キャプチャセッション自体の処理はGCDを使ってメインスレッド以外で行われる。
(これはキャプチャセッションで行なっている処理がメインの処理に影響を与えないため)
なので、キャプチャセッションのデリゲートメソッド内でUI関連の処理を書いても全く処理されない。
要は、UI関連はメインスレッドで実行するように記述せなあかんということ。

以下、ドキュメントの抜粋。
http://developer.apple.com/jp/devcenter/ios/library/documentation/AVFoundationPG.pdf

サンプルバッファのデリゲートメソッドの実装

デリゲートクラスには、サンプルバッファが書き込まれたときに呼び出されるメソッド
(captureOutput:didOutputSampleBuffer:fromConnection:)を実装します。ビデオデータ出力オ
ブジェクトはフレームをCMSampleBufferとして配信するため、CMSampleBufferをUIImageオブジェ
クトに変換する必要がありますこの操作の機能は、「CMSampleBufferからUIImageへの変換」に示しています。
- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection 
{
    UIImage *image = imageFromSampleBuffer(sampleBuffer);
    // 画像を使用するコードをここに追加する
}

んで、ここにちゃんと書いてあった。ドキュメントはエラいね。本当に。

このデリゲートメソッドはsetSampleBufferDelegate:queue:で指定したキュー上で呼び出されま
す。ユーザインターフェイスを更新したい場合は、関連するコードをメインスレッド上で呼び出す
必要があります。

上記のデリゲートメソッド内でもメインスレッド上で呼び出すためにはこんな感じで書けばよいかな。

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection 
{
    UIImage *image = imageFromSampleBuffer(sampleBuffer);
    if(boolItem)//特別な条件下(たとえば撮影するなど)
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self someMainThreadMethod:uiImage];
            });
    }
}