WWDC 2019で個人的に一番驚いたのがSwiftUIの登場です。これまで噂はあったものの、今年の目玉はUIKit for Macだと思っていたのでびっくりしました。
SwiftUIがiOS開発にどのような影響を与えるのか考えてみました。
SwiftUIの仕組み
SwiftUIは宣言型の構文(declarative syntax)で、Swift 5.1のEmbedded DSLsの機能を使って実装されています。具体的にはOpaque Result Type, Implicit ReturnやProperty Delegates, Function Builderといった機能が使われています。
従来のUIKitやAppKitを使ったプログラミングは大きな問題がありました。それはUIの状態(ステート)と、その状態を表す変数を同期するのが難しかった事です。特に別スレッドによる処理(ネットワーク接続等)やアニメーションを使う場面で、UIの動きとステート変数を正しく同期させるのは至難の技です。
SwiftUIはこの問題を2つの仕組みによって解決します。ひとつは@State
プロパティを使ってUIの状態とステート変数(Souce of truth)を自動的に同期する仕組みです。ステート変数を変更するとUIが更新され、またUIを変更するとステート変数が更新されるようになり、開発者が同期する必要がなくなります。
もうひとつはUIの構築や更新を行うコードを1箇所にまとめることです。UI関連のコードはすべてView
のbody
プロパティに記述することにより、従来のように複数箇所のコードが別々にUIの状態を監視したり変更したりする事がなくなります。またUIの変化をアニメーションで表現することも非常に簡単に行えるようになります。
SwiftUIは他にも@Binding
やBindableObject
, Combineフレームワーク等の仕組みがありますが、これらは別記事で紹介したいと思います。
UIKit / AppKitとの関係
SwiftUIで宣言されたUIは、iOSではUIKit, macOSではAppKitを使って表示されます。ただし、宣言された通りのコントロールがそのまま1対1でUIKitやAppKitのビューに置き換えられるわけではなく、システム側で最適な表示方法に変換されます。例えばView
の中のText
はUILabel
で表示されず、UIView
でプライベートAPIのCGDrawingViewが使われて表示されます。またVStack
やHStack
もビューには変換されないため、パフォーマンスに影響はありません。
宣言型の構文の良いところはこのような実装を気にする事なくUIを構築できる点にあります。実行時にiOS, macOS, watchOS, tvOSでそれぞれ最適なビューで表現されます。またダークモードや言語、Dynamic Typesなどの環境が実行時に自動的に反映される点も、宣言型構文のメリットです。
SwiftUIはUIKitやAppKitのビューに混在させる事が可能です。SwiftUIで宣言されたビューはUIHostingController
にラップしてUIViewController
として使うことができます。逆に、View
の中にUIView
を使う場合はUIViewRepresentable
を使います。例えばSwiftUIではマップビューを宣言することができませんが、UIViewRepresentable
を使ってMKMapView
を利用することが可能です。
SwiftUIがもたらす影響
このような仕組みを持つSwiftUIですが、iOS開発者に与える影響も非常に大きくなります。
まずひとつはUIの更新やアニメーションなどの扱いがシンプルになるため、バグの少ないコードが書けるようになります。SwiftがOptional
という概念を用いてnil
に起因するバグを大幅に減らしたように、@State
や@Binding
などを使うことでUIの状態とステート変数の乖離に起因するバグやクラッシュなどが確実に減ると思われます。
また現在はdelegate
やtarget-action
, key-value-observing
などに混在している非同期処理も、Combineフレームワークを使うことによって一連の流れにまとめることができるようになり、バグを減らすことができるようになると思われます。やや学習コストは高いですが、SwiftUIやCombineフレームワークは開発者にとって強力なツールとなりそうです。
また従来のModel-View-Controller(MVC)のアーキテクチャにも影響がありそうです。MVCにおけるコントローラーの役割のひとつにモデルとビューの同期がありますが、SwiftUIでは前述の仕組みでこれが自動的に行われるからです。また画面遷移の場合も従来はUIViewController
をpushしたりpresentしたりしていましたが、SwiftUIではdestination
に新しいView
を指定する形になり、コントローラが不要となります。
またUIViewController
が担っていたviewDidAppear
などのライフサイクルも、SwiftUIではView.onAppear()
に記述できるようになるなど、コントローラの役割が確実に減ってきています。
SwiftUIの今後
SwiftUIは非常に革新的な技術ではありますが、まだ機能不足な点がいくつか見受けられます。例えばマップやコレクションビューを宣言的に使う事ができません。またScrollView
のcontentOffset
を監視したり更新したりすることもできません。拙作カレンダーアプリで実装している無限スクロールも難しそうです。
言われてみれば納得なんだけど、今のところSwiftUIでScrollViewのオフセットを監視したり、外から与えてProgrammaticallyにスクロール位置を変えたりはできない。 #WWDC19
— kishikawa katsumi (@k_katsumi) June 7, 2019
さらにSwiftUIはアーキテクチャに関わる仕様が抜け落ちています。仮に新規プロジェクトで全面的にSwiftUIを採用したとしても、これまで通りUIApplicationDelegate
やUIViewController
、UIAlertViewController
等を使う必要があり、アップルはMVCを使い続けるのか、それとも別のアーキテクチャを採用するのかを開発者に示す必要があります。また複雑なジェスチャーにはUIGestureRecognizer
を使う必要があり、さらに複雑なレイアウトにはAutoLayoutを使う必要もあります。
今のSwiftUIはSwift 1.0の時のような衝撃がある一方で、未熟さも多々見られます。SwiftUIが今後どのように発展し、どこまで出来るようになるか注目していきたいと思います。
追記: Opaque Result Type
SwiftUIのsome Viewという部分は、その関数を呼ぶコードからはViewプロトコルとしてしか扱えないため実装上の型を隠蔽できるというメリットがあり、またコンパイラは本来の型(TextとかListとか)が分かっていて最適化もできるしパフォーマンスにも影響が出ない、といういいとこ取りのイメージ。
— tamadeveloper@Watchアプリできました (@tamadeveloper) June 10, 2019
参考
SwiftUI Tutorial
https://developer.apple.com/tutorials/swiftui/tutorials
Embedded DSLs in Swift / What's New in Swift
https://developer.apple.com/videos/play/wwdc2019/402/ (31:15~)
Implicit returns from single-expression functions
https://github.com/apple/swift-evolution/blob/master/proposals/0255-omit-return.md
Property Delegates
https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-delegates.md
Source of truth / Introducing SwiftUI: Building Your First App
https://developer.apple.com/videos/play/wwdc2019/204/ (20:45~)
Data Flow Through SwiftUI
https://developer.apple.com/videos/play/wwdc2019/226/
Introducing Combine
https://developer.apple.com/videos/play/wwdc2019/722
Inside SwiftUI’s Declarative Syntax’s Compiler Magic
https://medium.com/swift2go/inside-swiftuis-declarative-syntax-s-compiler-magic-df9336d640f3
SwiftUI’s relationship to UIKit and AppKit
https://wwdcbysundell.com/2019/swiftui-relationship-to-uikit-appkit/
Swift 5.1 に導入される Opaque Result Type とは何か
https://qiita.com/koher/items/338d2f2d0c4731e3508f
SwiftUIでの画面遷移とプレゼンテーション
https://qiita.com/H_Crane/items/eb847ca7fb7a0b9e8073
一部の画面だけSwiftUIを使いたいとき
https://qiita.com/owen/items/73473cd2206afda3c5d4