Help us understand the problem. What is going on with this article?

[SwiftUI]UIViewRepresentableにおける差分更新を最適化する

SwiftUIでは、UIViewをSwiftUIの世界に持ち込む際にUIViewRepresentableを利用します。
UIViewRepresentableはラップするUIViewのassociatedtypeと、UIViewの生成と更新を行う関数を保証するprotocolです。

public protocol UIViewRepresentable : View where Self.Body == Never {
    associatedtype UIViewType : UIView
    func makeUIView(context: Self.Context) -> Self.UIViewType
    func updateUIView(_ uiView: Self.UIViewType, context: Self.Context)
}

UIKitを使っていると、このUIViewRepresentableこそがビューの実体であるように思えますがUIViewRepresentableはあくまでもUIViewの生成と更新を行うだけでありUIViewのインスタンスはSwiftUIが独自に管理することになります。

さて、SwiftUIはビュー構造の中で変数が更新されるとbodyを再評価します。
通常SwiftUIのコンポーネントは内部的に差分の確認を行いますが、UIViewRepresentableの場合は無条件に更新関数がコールされます。

つまり更新関数の中で負荷の高い処理が行われている場合、その処理の結果が等価である場合も処理が通過してしまうということです。
これを防ぐ方法として、最終的にUIViewに渡す変数を全て保持しておけば良いですが実際はUIViewRepresentable側に隠しておきたいこともあると思います。

私の場合は、hashValueを元に前回の更新内容を比較して同じであれば処理をしないような以下のprotocolを定義しました。

protocol UIViewOptimizedRepresentable: UIViewRepresentable {
    associatedtype Value: Hashable
    var value: Value { get }
    init(_ value: Value)
    func shouldUpdateUIView(_ uiView: Self.UIViewType, context: Self.Context)
}

extension UIViewOptimizedRepresentable {
    func updateUIView(_ uiView: Self.UIViewType, context: Self.Context) {
        guard uiView.tag != self.value.hashValue else { return }
        shouldUpdateUIView(uiView, context: context)
        uiView.tag = self.value.hashValue
    }
}

hashValueはtagに隠していますが、気に入らない方はObjCRuntimeで隠しても良いと思います。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away