⬜
UIViewRepresentableにおける差分検出をどこで行うか
UIViewRepresentable
を使うことで、SwiftUIの世界にUIKitのビューを持ち込むことができます。
UIViewRepresentable
は以下のメソッドを要求するprotocolです。
func makeUIView(context: Self.Context) -> Self.UIViewType
func updateUIView(_ uiView: Self.UIViewType, context: Self.Context)
さて、ここで次のようなSwiftUIのbodyがあったとしましょう。
var body: some View {
UIKitView()
.environment(\.color, .red)
.environment(\.font, .bold)
}
すると、UIKitView
はfunc updateUIView(_ uiView: Self.UIViewType, context: Self.Context)
の中でenvironmentの値をUIKitのビューに反映させることになります。
uiView.color = context.environment.color
uiView.font = context.environment.font
ここで問題になるのは、updateUIView
がどの値の変更によって呼ばれたのか分からないという点です。
値をセットすることが高コストなAPIの場合、無関係の値の更新によって毎回高コストなAPIが呼ばれることになります。
これを回避するには、updateUIView
の中で前回の値と同じであれば高コストの処理をスキップする必要があります。
この処理は、本来はUIKitのビュー側で行うべき処理なので、updateUIView
に直に書かず、以下のようにoldValue
を参照して後続の処理を実行します。
副次的にUIKitで直接利用する場合でもパフォーマンスが最適化されます。
var color: ColorType = .default {
didSet {
if color != oldValue {
updateProcess()
}
}
}
ピュアなSwiftUIの場合、bodyの中での差分最適化に注目しますが、UIViewRepresentable
の場合はUIKitに頭を切り替える必要があります。
Discussion