*

Swiftでcapture StillImage Asynchronously From Connection – コタツと台所にて作るアプリ 12

      2015/10/28

PAK74_ookawajidori1209500

さすがに肌寒くなってきた11月のある日。

コタツに丸まりながら、居間に鎮座するソファにiPhoneを向けて、もう何度目かわらかないシャッターを切る。

MBAとケーブルでつながれたiPhone6には、開発中のアプリのカメラ画面が表示されていたが、シャッターを切ったら、次の画面へと遷移した。

それを見届けてから、ホームボタンを押してカメラロールを確認する。

さきほどシャッターを切った写真が、ちゃんと保存されていた。

「おおおぉぉぉ!やっっったぁぁぁぁー!」

バンザイしながらそのまま私は後ろに倒れこんだ。

Swiftでblock構文を書き直す。

前回の続きです。

block構文をSwiftで書き直していくのですが、いろいろと書き方をどうすればいいのか悩みました。

そんな中、参考にしたのが以下のソースです。

iOSSwiftOpenGLCamera

このソースはSwiftで書かれていて、captureStillImageAsynchronouslyFromConnectionの部分も載っています。

これを参考に作ったのが、以下のソースです。

//MARK: 撮影
    func takePhoto(completion:((image:UIImage?,error:NSError?)->Void)?){
        
        //ビデオ出力に接続
        let myVideoConnection = captureImageoutput.connectionWithMediaType(AVMediaTypeVideo)!
        
        //画像の向きを調整する。
        if (myVideoConnection.supportsVideoOrientation){
            //後で
        }
        
            //接続から画像を取得
  self.captureImageoutput.captureStillImageAsynchronouslyFromConnection(myVideoConnection, completionHandler: { (imageDataBuffer, error) -> Void in
                
                if(imageDataBuffer == nil){
                    completion!(image:nil,error:error)
                }

                // 取得したImageのDataBufferをJpegに変換.
                let imageData : NSData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataBuffer)!
                
                // JpegからUIIMageを作成.
                let myImage = UIImage(data: imageData)!
                
                completion!(image:myImage,error:nil)
                
            })

    }

書くとあっさりなんですが、ここまでたどり着くのに、かなり時間がかかりました。

さらにこのtakefotoメソッドの呼び出しもクロージャに合わせる必要があります。

//撮影
    func cameraTapped(sender: UIButton){
        cameraManager.takePhoto({image,error in
            
            //フォトマネージャーにイメージを設定
            let photoManager = MDPhotoImageManager.getInstance
            photoManager.setPhotoImage(image!)
            
            //Select画面に遷移
            self.performSegueWithIdentifier("camera_select", sender: nil)
        
        })
    }

MADOのソースをそのままコピーしているので、わかりずらいのですが、cameraManagerがtakePhotoのメソッドを定義しているクラスです。

MDPhotoImageManagerが写真を管理しているシングルトンのクラスで、そこに撮影したイメージを渡してあげて、次の画面でも使えるようにします。

イメージを設定したら、performSegueWithIdentifierで、次の画面に遷移します。

そして、イメージ設定と画面遷移をtakePhotoのinの中に記述します。

こうすることで、takePhotoメソッド内のcaptureStillImageAsynchronouslyFromConnectionがイメージを取得後に、処理が走るようになります。

最初はイメージ設定と画面遷移をtakePhotoメソッドの後に記述していたのですが、その書き方だと、イメージが取得される前に画面遷移までが実行されてしまい、次の画面で写真イメージがない状態になっていました。
(この非同期の動きを理解するのに結構時間がかかりました。。。)

難しいものでも諦めなければいつかは答えにたどり着く(はず。)

今回はこれを見ればOK!という、ドンピシャな資料もあまりなく、StackOverflowなどの英語サイトも見ながらあれこれ試していました。

最初は、何のこと言ってるのかよくわからないことも多かったのですが、テストを繰り返すうちに、なんとなく挙動が理解できて、その結果、わからなかった資料も実は大事なヒントが書かれていたということもあって、なんとか解決の糸口を見つけることができました。

諦めないで、調べればなんとかなるもんですね。(なんとかならないものもありますが。)

 - Swift, Xcode, アプリ