[SwiftUI] UIViewRepresentable を使う時に気をつける点 ( NSViewRepresentable も同様)

SwiftUI

UIKit や AppKit の View を SwiftUI と一緒に使う時に UIViewRepresentable や NSViewRepresentable を使いますが、その時に気をつけることを説明します。

環境&対象

以下の環境で動作確認を行なっています。

  • macOS Big Sur 11.1
  • Xcode 12.3
  • iOS 14.2

以下では、UIViewRepresentable で説明していますが、NSViewRepresentable でも同様です。

UIViewRepresentable

SwiftUI に不足なビューがあると、UIViewRepresentable で wrap して、組み込むことができます。

UIViewRepresentable プロトコルでは、2つのメソッドが指定されています。

以下は、NSAttributedString を表示するために作った AttributedText のコードです。

AttributedText
コード解説
  1. 最初にビューが構築される時に呼ばれます。UIKit の UILabel を使いたかったので、インスタンス化して返しています
  2. 表示すべき内容を更新する時に呼ばれます。表示に使用しているデータが更新された時等が呼ばれるタイミングです。当初は必要ないと思って、実装していませんでした。

気をつけなければいけない点

先ほど、updateUIView が、「表示に使用しているデータが更新された時に呼ばれる」と説明しましたが、他にも呼ばれるタイミングがあります。

上位ビューから再構築(body の再評価)されたときに、SwiftUI 側で判断によっては、すでにインスタンス化されている カスタム View を再利用しようとするタイミングでも updateNSView が呼び出されます。

つまり、新しいデータと共にビューが instance 化されると思っていると、SwiftUI 的には「すでに View があるんだから、データを更新すれば再利用できるハズ。なので、新しい instance を作らずに、既存の instance を update して使おう」と考えるということです。

アプリの動作としては、「データが切り替わっているはずなのに表示が切り替わらない」という動作になり、ハマります。

親ビュー含め丸ごと更新されるから、カスタム View も再構築されると想像してしまいがちですが、上記のようなケースもあるため updateNSView も実装しておいた方が良いです。

makeUIView でなく、updateUIView が呼ばれる例

# 短いコードで表現したかったので、少し無理やりです。

App

アプリの動作としては、データの配列がアプリ内に保持されていて、+ボタン/ーボタンを押すことで、その配列の要素を順番に確認できるという動作です。

期待動作

updateUIView を未実装にすると、以下のような動作に変わります。

まとめ:ViewRepresentable を使う時に気をつけるべき点

ViewRepresentable を使う時に気をつけるべき点
  • updateNSVIew/updateUIView は、予期しないタイミングで呼ばれるケースがあるので、必ず実装する
  • updateNSVIew/updateUIView が呼ばれない前提であれば、チェックする仕組みを入れておく

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です