ComposableArchitectureで同一フレームの実行を防ぐ

ComposableArchitectureで同一フレームの実行を防ぐ

作成日
May 9, 2021 3:54 PM

Composable Architectureを使っていると、syncなEffectは同じメインスレッドのフレームで実行されます。

例えば次のような処理の2つのprintは同じタイミングで実行されます。

case .actionA:
print("Action A")
return Effect(value: .actionB)
case .actionB:
print("Action B")
return .none

これは処理の観点では効率的ですが、この挙動が望ましくないこともあります。

例えば、iOSではpushとmodalの処理を同じフレームで実行することが出来ません。

UIKitではviewDidLoadにpresentを書いて実行されない経験がある方も多いと思いますが、同じ現象がSwiftUIでも発生します。

また、アニメーションがミックスされてしまうこともあります。

この問題を解消するには、前後で別のフレームで実行する必要があります。

UIKitではDispatchQueue.main.asyncの中で呼ぶことで実現できますが、TCAの場合次のようにしてsubscribeで使うスケジューラを明示的に指定します。

case .actionA:
print("Action A")
return Effect<Action, Never>(value: .actionB)
                    .subscribe(on: DispatchQueue.main.eraseToAnyScheduler())
                    .eraseToEffect()
case .actionB:
print("Action B")
return .none

そうすると、一度処理はasyncとして保持されactionAが完了したのち新規にacitonBを実行するスケジューラが開始します。