Composable Architectureにおけるカメラ制御の扱いのお悩み相談

公開:2021/02/02
更新:2021/02/02
2 min読了の目安(約2600字TECH技術記事 2

こんばんは。やっと技術っぽいこと書き始めたアマゾネスです。
...といっても有益な知識共有とかではなく、お悩み相談です。ごめんなさい。

現在The Composable Architecture(以下、TCA)の構成でアプリを実装しているのですが、カメラを使用するにあたり、とても考えていることがあるで、それを共有&お力をかりたい感じです🙇‍♀️

悩んでいること

はじめに悩んでいるポイントをいいます。

前提:TCAで実装している

  • カメラのセッション開始や終了はReducerで扱うべきか
  • ViewをStateとして扱うことに違和感を感じないか

が、今回のお悩みポイントです。

それを踏まえ、中身の簡単な実装を書いていきます。
実装物は、起動時にカメラが表示されるだけのアプリです。

実装

SwiftUIでカメラを扱う場合、UIViewControllerRepresentableに準拠したCALayerViewを用意する必要があります。
※アーキテクチャは違いますが、全体の実装としてはこちらを参考にさせていただいています。

CALayerViewはキャプチャされたビデオを表示する必要があります。
キャプチャしたビデオはCALayerのサブクラスであるAVCaptureVideoPreviewLayerで表示することができるので、それをプロパティに持ちます。

struct CaptureView: View {
    var body: some View {
        ZStack {
            CALayerView(caLayer: AVCaptureVideoPreviewLayer)
        }
    }
}

次に、カメラ制御を責務とする AVFoundationManagerを用意しました。
このクラスでは、AVCaptureDeviceAVCaptureSessionクラスを使用してカメラの設定や制御を行ったりします。CALayerViewに渡す必要があるAVCaptureVideoPreviewLayerはCaptureSession組み合わせた状態である必要があるので、このクラスで生成されます。詳細

そうすると、以下のような実装になってくると思います。

struct CaptureView: View {
    var avFoundationManager: AVFoundationManager
    var body: some View {
        ZStack {
            CALayerView(caLayer: avFoundationManager.previewLayer)
            }
            .onAppear {
                avFoundationManager.startSession()
            }
            .onDisappear {
                avFoundationManager.endSession()
            }
    }
}

これでカメラが起動した画面は表示されます📷

が、

TCAを使用する場合、AVFoundationManagerEnvironmentにもたせて、Reducerでカメラの起動を扱うこともべき? とか考え始めました。
ただこの場合、avFoundationManager.previewLayerStateとして扱う必要がでてきます。

大体こんな感じ。

struct CaptureEnvironment {
    var avFoundationManager : AVFoundationManager
}

let captureReducer = Reducer<CaptureState, CaptureAction, CaptureEnvironment> {
    state, action, environment in

    switch action {

    case let .onAppear:
        environment.avFoundationManager.startSession()
        state.previewLayer = avFoundationManager.previewLayer
        return .none

    case .onDisappear:
        environment.avFoundationManager.endSession()
        return .none

    }
}

まとめ

冒頭でもお伝えした通り、気になっているポイントとしては

  • カメラのセッション開始や終了はReducerで扱うべきか
  • ViewをStateとして扱うことに違和感を感じないか

の二つになります。

私ははじめ、カメラのセッション開始や終了はReducerで扱う形で実装していました。
ですが、View自体をStateとして扱うことに違和感があったり、要件的にカメラ状態はViewの生存と一蓮托生なのでReducerで扱う必要ないんじゃないかとかいろいろ悩んでいる、なうです。

いいアイディアや、ご意見ご感想、お待ちしています🙏