LoginSignup
2
2

More than 5 years have passed since last update.

AVCam-iOSをReactiveCocoa4で実装し直してみる

Last updated at Posted at 2016-05-10

開発環境

  • XCode7.3
  • Swift2.2
  • ReactiveCocoa4

Reactiveとは

ここが分かりやすかった
古くて新しいリアクティブプログラミングのすすめ-Frontrend Conference

最初に紹介したReactiveについての解説よりは実装的な解説があって分かりやすい。ObjC、SwiftではなくRxJSというJavaScriptのフレームワークを使って解説しているけど。

「RxJS」初心者入門 – JavaScriptの非同期処理の常識を変えるライブラリ

結論としては、MVVMというアーキテクチャを実装するのに使われるのがReactive・・・で合ってるかな?

iOSアプリで実装するには

選択肢は大雑把には二つ

  • ReactiveCocoa
  • RxSwift

RxSwiftより前に知ってたので、ReactiveCocoaを選択。

ReactiveCocoaとは

ReactiveCocoa

iOSアプリ開発界では先発組だったけど、ObjCからSwiftへの転換は比較的最近。なので資料(googleでの検索結果)が圧倒的にObjC時代のが多く、今のSwiftでのやり方がすぐに見つからない場合もあります。

導入方法

手動、Pods install、Carthageと色々あるけど今回はCarthageにしました。
Pods installと似てるけど、Carthageの方がプロジェクトに対する影響が小さいようです。こちらの方が好みですね

Carthageの具体的な使い方は以下を参照
Carthageを使ってビルド時間を短縮しよう
ReactiveCocoa <- ReadMeにやり方載ってます

実装

お手頃なのが無かったので、とりあえず先日作ったAVCam-iOSをReactiveCocoaを使って作り直してみました。
先に結論を言っておくと、あまり適当な例では無かったw
作ったものはgithubにあげてあります。

AVCamRCSample

やり方がすぐにわからなかったのをピックアップ。
例えば以下のようなボタンのタップに対するActionをReactiveCocoaで実装しようとすると

CameraViewController.swift

    @IBAction func resumeInterruptedSession(sender: AnyObject) {
        dispatch_async(self.sessionQueue, {
            self.session.startRunning()
            self.sessionRunning = self.session.running
            if(!self.session.running){
                dispatch_async(dispatch_get_main_queue(), {
                    let message = NSLocalizedString("Unable to resume", comment: "Alert message when unable to resume the session running")
                    let alertController = UIAlertController(title: "AVCam", message: message, preferredStyle:.Alert)
                    let cancleAction = UIAlertAction(title: NSLocalizedString("OK", comment: "Alert OK button"), style: .Cancel, handler: nil)
                    alertController.addAction(cancleAction)
                    self.presentViewController(alertController, animated: true, completion: nil)
                })
            } else {
                dispatch_async(dispatch_get_main_queue(), {
                    self.resumeButton.hidden = true
                })
            }
        })
    }

こういう形になる

CameraViewController.swift

        let resumeInterruptedSessionAction = Action<AnyObject, Void, NSError>{ _ in
            dispatch_async(self.sessionQueue, {
                self.session.startRunning()
                self.sessionRunning = self.session.running
                if(!self.session.running){
                    dispatch_async(dispatch_get_main_queue(), {
                        let message = NSLocalizedString("Unable to resume", comment: "Alert message when unable to resume the session running")
                        let alertController = UIAlertController(title: "AVCam", message: message, preferredStyle:.Alert)
                        let cancleAction = UIAlertAction(title: NSLocalizedString("OK", comment: "Alert OK button"), style: .Cancel, handler: nil)
                        alertController.addAction(cancleAction)
                        self.presentViewController(alertController, animated: true, completion: nil)
                    })
                } else {
                    dispatch_async(dispatch_get_main_queue(), {
                        self.resumeButton.hidden = true
                    })
                }
            })

            return SignalProducer.empty
        }

        resumeButton.addTarget(resumeInterruptedSessionAction.unsafeCocoaAction, action: CocoaAction.selector, forControlEvents: .TouchUpInside)


ジェスチャーの場合は以下のようにしてたものを

CameraViewController.swift
    @IBAction func focusAndExposeTap(gestureRecognizer: UITapGestureRecognizer) {
        let devicePoint = (self.previewView.layer as! AVCaptureVideoPreviewLayer).captureDevicePointOfInterestForPoint(gestureRecognizer.locationInView(gestureRecognizer.view))
        self.focusWithMode(AVCaptureFocusMode.AutoFocus, exposeWithMode: AVCaptureExposureMode.AutoExpose, atDevicePoint: devicePoint, motiorSubjectAreaChange: true)
    }

このように変更する

CameraViewController.swift
        let gesRect = UITapGestureRecognizer()
        self.previewView.addGestureRecognizer(gesRect)
        gesRect.rac_gestureSignal().toSignalProducer().map({ (x) -> CGPoint in
            return (self.previewView.layer as! AVCaptureVideoPreviewLayer).captureDevicePointOfInterestForPoint(x!.locationInView(x!.view))
        }).startWithNext { (pointInView) -> () in
            self.focusWithMode(AVCaptureFocusMode.AutoFocus, exposeWithMode: AVCaptureExposureMode.AutoExpose, atDevicePoint: pointInView, motiorSubjectAreaChange: true)
        }

結論

まあお試しなんで良いも悪いもないのですが、今回のサンプルではまだReactiveのメリットを試しきれてないので、もう少し恩恵を受けやすい形のサンプルを用意して試してみたいと思います。

追記

参考になるサイト

ReactiveCocoa勉強会関西を開催しました #rac_kansai

ReactiveCocoa and MVVM, an Introduction

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2