Composable Architectureにおけるカメラ制御の扱いのお悩み相談
こんばんは。やっと技術っぽいこと書き始めたアマゾネスです。
...といっても有益な知識共有とかではなく、お悩み相談です。ごめんなさい。
現在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
を用意しました。
このクラスでは、AVCaptureDevice
や AVCaptureSession
クラスを使用してカメラの設定や制御を行ったりします。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を使用する場合、AVFoundationManager
をEnvironmentにもたせて、Reducerでカメラの起動を扱うこともべき? とか考え始めました。
ただこの場合、avFoundationManager.previewLayer
をStateとして扱う必要がでてきます。
大体こんな感じ。
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で扱う必要ないんじゃないかとかいろいろ悩んでいる、なうです。
いいアイディアや、ご意見ご感想、お待ちしています🙏
Discussion
PointFreeのTCAシリーズも見ましたけど、実装することがまったくないのでアドバイスとか言えませんが。
TCAを採用した一番のメリット(解決したい問題とも言える)は、外部から発火した Action による State 変化も観察できるや、外部からローカル状態を操作できることとかじゃないですか?
(ディテール画面のいいねはリストにも反映するや、URL Schemeによるアプリ起動後の状態設定など)
そうすると、もし、カメラの初期挙動が、外部から設定することはまったくないなら(今後の機能拡張も考えた上)、一つ目の簡単なほうがいいんじゃない?わざわざTCAに従って複雑度を上げる必要はないと思います。
自分もTCAの動画を見る時結構悩みます、UI上の状態は一体Storeに属するべきかどうかという問題。属すると、SwiftUIならまだしも、UIKitなら異常に面倒くさくなる感じがします。後期の動画は見てなかったので、UI状態管理に関する問題に触れたのかな...
生産環境でTCAを実装したどの方からアドバイスを貰えるといいですね。
コメントありがとうございます!とても嬉しいです!
現在の実装パターンだと、カメラのセッションとViewの生存と一蓮托生なので、動的な状態管理は実際必要ないんですよね。なので、おっしゃる通り、頑張ってTCAに従って複雑度を上げる必要はないのかもしれません。
それから、実際TCAを実装した方から↓というアドバイスいただきました!
このコメントをみて、AVFoundation関係はViewとして扱う方が結果的にシンプルになりそうな気がしました。
これには完全同意です!!
現在実装しているアプリにはもちろん撮影以外の画面があるのですが、UIKitを使用する撮影画面っがめちゃくちゃ面倒臭そうだったので、先に実装して、TCAを採用しても本当に大丈夫なのか検証してました。
結果としては良さそうな気がしています💡