SwiftUIとUIKit、結局どっちを使えば良いのかを考える

# SwiftUIとUIKit、結局どっちを使えば良いのか

SwiftUIがUIKitの後継のように登場し、これからの開発においてSwiftUIを使うべきなのか悩んでいる開発者も多いと思います。
この記事では、いろいろな角度からSwiftUIとUIKitの立ち位置を考えてみます。

## マルチプラットフォームから考える

ここでのマルチプラットフォームとは、iOSとAndroidのことではなくAppleプラットフォームの上での違いを指します。
具体的には現在はmacOS, iOS, iPadOS, tvOS, watchOSが各プラットフォームを指します。

![https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/b7f19a92-d4dd-0be6-cf31-7b6d6dda11c5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/b7f19a92-d4dd-0be6-cf31-7b6d6dda11c5.png)

SwiftUIの特徴として、プラットフォーム固有のAPI[^1]を除けば全く同じソースコードで上記の全てのプラットフォームでアプリケーションを実行することができます。
UIKitも、watchOSを除くmacOS, iOS, iPadOS, tvOSの開発をすることができます。

両者ともプラットフォームのカバー範囲は十分に広いと言えますが、実際にマルチプラットフォームのアプリを開発する場合は、それぞれのプラットフォームに最適化されたUIを提供する必要が出てきます。

例えば、同じボタンでも以下のようにマウスでクリックしやすいUIを提供する必要があります。

![CleanShot 2022-03-16 at 01.07.34@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/e84645d5-1111-4e8d-7125-064bce8a8659.png)

SwiftUIは、自動的にプラットフォームに最適化されたUIを構築します。

UIKitの場合は、CatalystのOptimize Interface for Macを有効にすることでこれらのUIを自動的に変換することができます。

ただし、これらの変換が上手くいくのはあくまでUIKitをピュアに使ったケースに限ることが多いです。

つまりCatalystのOptimizerを上手に使うには、UIKitが提供するカスタマイズ性の中でアプリを完結する必要があるということです。

そうなるとUIKitはただのレガシーな記述をするUIフレームワークに成り下がってしまいます。

こうなるとSwiftUIを使う方が得策と言えるでしょう。

## 未来のプラットフォームを考える

AppleはVRHMDやARグラス、AppleCarなどの製品をリリースすると考えられます。

その時にmacOSのようにUIKitを動作させる環境を用意するでしょうか？

Catalystはあくまでmacアプリの普及のための存在であり、新しいプラットフォームでサポートしないのではないかと筆者は思っています。

特にARグラスのようなバッテリーライフに厳密なプラットフォームでは、ウィジェットのようにSwiftUIオンリーの開発環境を整えることが予想されます。[^2]

将来の新プラットフォームで、既存のアプリの資産を活かせる可能性が高い点はSwiftUIを選ぶメリットになります。

## ユーザー最適化の観点から考える

SwiftUIは、マルチプラットフォームの挙動を見れば分かる通り、描画されるUIの結果を直接構築するものではありません。

これは大なり小なり、同一プラットフォーム上でも確認することができ、例えばTextは標準でDynamic fontとなっておりユーザーのアクセシビリティ設定によって大きさが異なります。

![CleanShot 2022-03-16 at 01.33.15.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/0449ed98-0662-2e52-2bef-8f9f87841568.gif)


例えるならば、コーヒーを頼んだ時に写真と同じカップで出て来るのがUIKit、飲む人の手の大きさや好みに合わせたカップで出て来るのがSwiftUIと言えるでしょう。

もちろんUIKitでもユーザーに対して最適化することは出来ますが、SwiftUIの場合は考慮していなくても自動的に対応されている状態になることが異なる思想と言えます。

アクセシビリティや言語対応は非常にコストがかかる点であるため、この点はメリットと言えます。

しかし、「写真と同じカップで出て来る」という体験がサービスにおいて非常に重要であるかどうかは一考の価値があります。

独自の世界観に完全に閉じ込めて没入させることが、多くのユーザーの操作性よりも重要な時はSwiftUIを使わない明確な理由になり得ます。

## 制約から考える

ユーザー最適化の代償として、SwiftUIではプラットフォームに最適化したいくつかの機能を失っています。

例えば、モーダルの画面遷移を細かく制御することができません。

SwiftUIはあくまでプラットフォームの共通項である「モーダルで出す」という宣言しかできず、そのアニメーションや、シートのリサイズをすることができません。

webで見つかるいくつかのSwiftUIのチュートリアルでは、これらを無理に実装するようなものも見受けられますが、それをしてしまうとプラットフォームやユーザーへの柔軟性が損なわれて破綻してしまうことが多いため注意が必要です。

これらの制約によって体験が成り立たない場合は、UIKitでの実装をおすすめします。

ただし`refreshable`など、プラットフォーム固有のUIコンポーネントも徐々に登場しているので、将来的に緩和される可能性はあります。

## 一部分の導入を考える

UIKitであれば、UIViewRepresentableを使って、SwiftUIにビューを埋め込むことができます。（AppKitにも同様のクラスがあります）

この機能を使うとSwiftUIのメリットが、埋め込まれた箇所だけ失われることになります。

つまり、真面目にやるのであれば埋め込まれるビューはプラットフォームやユーザーに最適化した動的なものを作る必要があります。

これは非常にコストが高いため、仮にUIViewRepresentableを使うのであればアプリに1,2個が限界ではないかなと思います。アプリを成り立たせる上でどうしても必要な箇所に絞るべきと言えます。

一方でUIHostingControllerを使うことでUIKitにSwiftUIのビューを埋め込むことができますが、こちらは比較的楽観的に使うことができます。

カスタマイズ性の求められない画面にSwiftUIを使うことでSwiftUIのDSLやユーザー最適化の恩恵を得ることができます。

将来的な細かい変更に弱い点は否めないため、導入は設定画面などの機能性が重視される画面が向いていると思います。

## 開発チームの構造から考える

SwiftUIはユーザーに最適化したUIを提供するため、ウォーターフォールのような開発環境では非常に扱うのが難しいと言えます。

基本的にはSwiftUIでは何が出来て何が出来ないという禅問答をデザイナーやプランナー、HR[^3]などと繰り返して進めることになります。

ここでのコツは、デザインファーストな議論にしないことが重要です。あくまで体験を中心に議論し、それを達成できる画面の情報設計だけを落とし込むことが重要です。

チームはデザインファーストにしないために、投資家やユーザーにリッチなモックアップよりも体験の良さを訴求する能力も求められます。

それだけの規模を巻き込めるかどうか、またそれでもSwiftUIを使う価値があるのかを見極めることが筆者はSwiftUIの一番の難しさであると言えます。

逆に、個人開発ではこれらの意思決定が自分に集中するため導入のハードルが低くなります。

# まとめ

結論、どちらを使うべきというのは当然簡単に答えが出るわけではありません。
これはアーキテクチャ同様、サービスの性質や開発体制の条件から適したものはどれなのかを探し出すタイプの問いだからです。
今回の記事ではいくつかの視点から、結論を導き出すための考察を紹介しました。
皆さんの技術選定のヒントになればと思います。

[^1]: 例えばfileImporterはwatchOSでは使えない [https://developer.apple.com/documentation/musickit/artworkimage/fileimporter(ispresented:allowedcontenttypes:allowsmultipleselection:oncompletion:)](https://developer.apple.com/documentation/musickit/artworkimage/fileimporter(ispresented:allowedcontenttypes:allowsmultipleselection:oncompletion:))

[^2]: フルSwiftUIで書かれている以上直接ビューを操作することが出来ず、実行環境によって動作を制限しやすいため

[^3]: SwiftUIは採用にはプラスなので