0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【開発日誌 Day16】2026年もUIKitで画面を描く理由を、歴史から確かめた

0
Posted at

前回まで、下書きの数や送信の速さといった、画面の「上」で起きることばかり測ってきた。だが、その画面そのものを何で描くかは、Day1より前に一度だけ決めて、以来ほとんど書き直していない。選んだのはUIKitだ。2026年のいま、新規iOSアプリの既定は誰がどう見てもSwiftUIで、「UIKit SwiftUI どっち」と検索すれば「新規ならSwiftUIで始めろ」という答えがまず出てくる。それでもこのアプリの画面は、いまだにUIKitが描いている。へそ曲がりだからではない。理由を、2008年までさかのぼって確かめる。

UIKitとSwiftUIは、機能の優劣で並ぶライバルではない。「画面とは何か」という問いへの、世代の違う2つの答えだ。だから新しいほうが常に正しいとは限らない。順番に見ていく。

2008年、UIKitは「画面は命令で組み立てるもの」として始まった

2008年7月、iPhone OS 2.0と一緒に最初のiOS向けSDKが公開された。UIKitはここで世に出ている。当時の、そしていまも変わらないUIKitの世界観は、ひとことで言えば命令的だ。UIViewを生成し、addSubviewで親に貼り、参照を手元に持っておき、必要になったらその参照を掴んでbackgroundColortextを書き換える。画面は、開発者が1つずつ手で積み上げ、あとから手で書き換える「もの」だった。

// UIKitの世界観:参照を持ち、命令で組み立て、命令で書き換える。
let label = UILabel()
label.text = "未送信:0件"
view.addSubview(label)
// あとで状態が変わったら、自分でこの参照を掴んで書き換える。
label.text = "未送信:\(outbox.count)件"

この「参照を持って、あとから書き換える」が、UIKitのすべての土台にある。UIViewControllerがライフサイクルを抱え、delegatetarget-actionでイベントを受け、Interface Builderの.xibで見た目を組む。2008年に決まったこの骨格は、18年近くたったいまもほとんど変わっていない。古いことは、ここでは欠点ではない。骨格が動かないからこそ、その上の知識は積み上がり、枯れていく。

2011〜2014年、命令的UIの上に道具だけが積まれていった

UIKitの骨格はそのままに、その上へ道具が足されていった時期がある。2011年のiOS 5でStoryboardが入り、画面遷移を線で結べるようになった。2012年のiOS 6で、iOSにもAuto Layoutが来て、座標の直書きから制約ベースのレイアウトへ移った。2014年には言語そのものが入れ替わり、Objective-CからSwiftへの長い移行が始まった。

ここで大事なのは、これらがどれも「命令的UIの上に乗った便利機能」であって、画面の作り方そのものは変えなかったことだ。Storyboardは巨大化すると差分が読めなくなり、Auto Layoutの制約は数が増えると衝突して「制約地獄」と呼ばれた。

もう少し言えば、この時期の痛みは「画面が複雑になるほど増える」種類のものだった。表示もロジックも1つのUIViewControllerに詰め込む肥大化が進み、数千行のビューコントローラは珍しくなかった。Auto Layoutの制約も、要素が10も20も増えれば、どれか1本が矛盾して画面全体が崩れる。皮肉な話だが、UIKitのつらさは、ほぼすべて「画面が多い・複雑だ」という前提の上で牙をむく。画面が1つで要素も数個のアプリは、この弱点をそもそも踏まない。後で効いてくるので、覚えておく。

Swiftは言語としては美しくなったが、UIKitの使い方はviewDidLoadで参照を組み立てる、あのままだった。つまり2014年の時点で、iOS開発は「新しい言語で、古い世界観のUIを書く」という捻れた状態にあった。この捻れが、次の答えを準備したと言っていい。

2019年、SwiftUIは「画面は状態の関数だ」と言い切った

2019年6月のWWDCで、SwiftUIが発表された。同時にCombineも来て、iOS 13から使えるようになった。SwiftUIの主張は、UIKitとは正反対と言っていい。画面は手で組み立てる「もの」ではなく、状態を渡すと姿が決まる「関数」だ、という立場をとった。状態が変われば、フレームワークが差分を計算して画面を描き直す。開発者は参照を持って書き換えない。状態だけを書き換える。

// SwiftUIの世界観:状態を宣言し、画面はその状態の写像として導かれる。
struct OutboxBadge: View {
    @State private var count = 0
    var body: some View {
        Text("未送信:\(count)件")   // countが変われば、ここは自動で描き直される
    }
}

同じ「未送信の件数を出す」でも、発想がまるで違う。UIKitはlabelという参照を覚えておき、自分で書き換える。SwiftUIはcountという状態だけを持ち、表示はそこから導かれる。どちらが正しいという話ではない。ただ、片方は2008年の、片方は2019年の「画面とは何か」だ。世代が11年離れている。

ただし2019年のSwiftUIは、思想は鋭くても実用はまだ粗かった。iOS 13と14の頃は、込み入ったリストやナビゲーションで素直に動かない場面が多く、難しい画面はUIKitに逃がすのが定石だった。思想が先に来て、実装が後から追いつく。新しいフレームワークの常で、SwiftUIもこの数年を通ってきた。

具体的には、iOS 13のSwiftUIはListの区切り線を思うように消せず、NavigationViewは深い遷移で状態を見失うことがあった。@State@Bindingで「状態を誰が持つか」を決める考え方も、UIKitに慣れた手には最初なじまない。だから当時の本気のアプリは、SwiftUIで外枠を作り、難所だけUIViewControllerRepresentableでUIKitに包んで逃がす、という折衷が多かった。新しい答えは、古い答えを必要としながら育った。ここも伏線として置いておく。

なぜ2023年まで「SwiftUIで全部書く」に踏み切れなかったのか

SwiftUIが「思想は良いが、まだ本番では怖い」を抜けたのは、自分の見立てでは2023年だ。この年のWWDCで、iOS 17と一緒にObservationフレームワークとSwiftDataが来た。

それまでのSwiftUIは、状態の変化をObservableObject@Publishedで伝えていた。だがこれは、オブジェクトのどれか1つが変わると、それを見ている画面が必要以上に描き直される作りで、規模が大きくなるほど無駄が増えた。Observationフレームワークは、@Observableマクロで「実際に読まれたプロパティが変わったときだけ描き直す」へ作り替えた。SwiftDataは、永続化をSwiftの型からそのまま宣言できるようにした。この2つで、SwiftUIはやっと「大きな本番アプリを最初から最後までこれで書ける」水準に届いた。「SwiftUI 本番」で検索して安心できる答えが増えたのも、だいたいこの時期からだ。

自分のアプリで言えば、ここで来たSwiftDataには手を出していない。送信キューの永続化は、Day3で書いたOutboxの素朴なファイルとCoreDataで既に足りていて、新しい永続化層を足す理由がなかったからだ。ただ、Observationが押し出した「読まれたものだけ描き直す」という考え方そのものは、状態を手で配るUIKit側の設計にも、規律として効いた。誰がどの状態を読んでいるかをはっきりさせる——この一点は、フレームワークが違っても変わらない。

だから時系列で見ると、SwiftUIが「既定」になったのは、2019年の登場時点ではない。実用の重心が移ったのは2023年だ。登場から既定まで、4年かかっている。新しい答えが古い答えを置き換えるには、思想の鋭さだけでは足りず、これだけの時間が要るということでもある。

2026年、既定はSwiftUIになった。ではなぜこのアプリはUIKitのままなのか

2026年のいま、状況ははっきりしている。新規アプリの既定はSwiftUIだ。スクロールやアニメーションといった普段づかいの性能はUIKitと並んだと言われ、複数のApple OSへ同じコードで展開できる強みもある。新しいAPIはSwiftUIから先に来る。これは認める。「UIKit SwiftUI どっち」の一般論で言えば、答えはもうSwiftUIで固まっている。もし自分がいま、画面の多いアプリや、iPhoneとMacの両方に出すアプリを新しく始めるなら、迷わずSwiftUIで書き始める。

それでもこのアプリの画面をUIKitで描いているのは、このアプリが「ほぼ1画面で、起動の速さがそのまま価値になる」という、かなり特殊な形をしているからだ。Day4で起動0.3秒を詰めた話を書いたが、キャプチャ専用アプリにとって、最初の0.3秒は機能の一部ではなく、機能そのものに近い。ここでUIKitには、地味だが効く性質がある。冷えた状態からの起動が、ベンチマークによってはSwiftUIより5〜10%ほど速いと報告されることだ。理由を乱暴にまとめれば、SwiftUIは起動時に状態とビューの対応関係を組み立てる土台を一度用意するが、UIKitは最初の1画面を出すだけならその土台が要らない。

// このアプリの起動経路。SceneDelegateで、最初の1画面だけを最短で出す。
func scene(_ scene: UIScene,
           willConnectTo session: UISceneSession,
           options: UIScene.ConnectionOptions) {
    guard let windowScene = scene as? UIWindowScene else { return }
    let window = UIWindow(windowScene: windowScene)
    window.rootViewController = ComposerViewController()  // 入力欄ひとつだけの画面
    window.makeKeyAndVisible()
    // 状態グラフの構築も、ビューツリーの差分エンジンも、ここでは動かさない。
}

差は数十ミリ秒の世界で、ほとんどのアプリでは誤差だ。だが、価値の全部が最初の0.3秒に乗っているアプリでは、この数十ミリ秒は誤差ではなく中身になる。Day6で外部依存をゼロにした話とも噛み合う。UIKitは2008年から積み上がった、いちばん枯れたApple純正の土台で、「初回だけなぜか重い」のような、新しい層が増えるほど起きやすい不具合の余地が少ない。Day7でHistoryの反映をSwiftで直したときも、UIKitとCoreDataの枯れた挙動の上だったから、原因を底まで追えた。

加えて、UIKitだけで組んだ最初の画面は、出るまでの経路が短く、毎回ほぼ同じ時間で立ち上がる。速いだけでなく、ばらつきが小さい。中央値だけでなく、いちばん遅い回までが揃うことは、1日に何十回も開く道具では地味に効いてくる。たまに引っかかる起動は、平均が同じでも、速いという印象を確実に削るからだ。

SwiftUIが遅いのではない、と言われたらどう答えるか

ここは公平に書く。いまの主張に対する、いちばん正しい反論はこうだ。「SwiftUIが起動を遅くするのではない。遅いのはアーキテクチャだ」。これは正しい。「SwiftUI 起動 遅い」で検索して出てくる答えの多くも、フレームワークではなく設計の問題を指している。実際、起動5.2秒のSwiftUIアプリを、設計を見直すだけで1.1秒へ縮めた、という報告もある。8割の短縮で、フレームワークのせいにできる差ではない。UIKitとSwiftUIを混ぜるときのUIHostingControllerの上乗せも、1%未満とされていて、無視していい。普段づかいの95%の場面で、SwiftUIは十分に速い。

もう1つ正直に付け加える。ユーザーが感じる速さは、計測上の起動時間とぴったりは一致しない。起動直後に空の入力欄へカーソルが乗り、すぐ打てる状態になっていれば、多少の差は体感に出ない。だからSwiftUIでも、設計が良ければ「十分速い」に届く。それでもUIKitを選ぶのは、体感を設計で稼ぐ前に、素の経路がもう速いほうが、守るべき0.3秒に余白が残るからだ。速さを設計で取り返す勝負を、そもそも始めなくて済む。

だから、自分はこう答える。UIKitを選んだのは、SwiftUIが遅いからではない。このアプリには「開発すべき画面」がほとんどないからだ。SwiftUIの最大の見返りは、UI開発の時間が3〜5割ほど縮むことにある。画面が多いアプリほど、この見返りは大きい。ところがこのアプリは画面が1つしかない。縮むはずの開発時間が、そもそも縮む対象を持っていない。一方で、失いたくない起動の数十ミリ秒と、層を増やさない安心は、画面が1つしかないからこそ相対的に重くなる。見返りが最小で、コストが最大になる側に、たまたまこのアプリは立っている。

これはDay15で書いた結論の出し方と、同じ筋だ。機能の良し悪しは単体では決まらず、いつも「何の道具か」とセットで決まる。SwiftUIが良いか悪いかではない。1画面のキャプチャ道具という用途に対して、いまはUIKitのほうが釣り合う、というだけの話だ。用途が変われば、答えも変わる。

UIKitを選んで、何を諦めたのか

UIKitを選ぶことは、ただではない。公平のために、諦めたものを正直に並べておく。まず、たった1画面でも、入力欄やボタンの配置は自分で制約を書いて組む必要がある。SwiftUIなら十数行で済む見た目に、UIKitでは何倍かのコードがかかる。次に、コードを書いてから画面で確かめるまでの往復が遅い。SwiftUIのライブプレビューのように、書いた端から見た目が出る速さは手に入らない。そして、同じコードでMacやApple Watchへ広げる道も、最初から捨てている。

これらは、画面の多いアプリなら確かに効いてくる損失だ。だが、ここでも同じ話に戻る。このアプリは画面が1つしかない。書くべきUIが少ないから、ボイラープレートの総量も、プレビューを我慢する回数も、たかが知れている。多プラットフォーム展開も、キャプチャ専用という用途には最初から要らない。UIKitの弱点はどれも「画面が多いほど痛い」もので、画面が1枚のこのアプリは、その痛みがいちばん小さい場所に立っている。損失を正直に数え上げても、なお釣り合っている——それが、この選択の現在地だ。

年表で見ると、答えはこう動いてきた

ここまでを1枚に畳む。

出来事 「画面とは何か」への影響
2008 iPhone OS 2.0、UIKit公開 画面は命令で組み立てる「もの」
2011 iOS 5、Storyboard 命令的UIの上に画面遷移の道具が乗る
2012 iOS 6、Auto Layout 座標の直書きから制約ベースへ
2014 Swift発表 言語は新しく、UIの世界観は据え置き
2019 SwiftUI/Combine(iOS 13) 画面は状態の「関数」だと宣言
2021 Swift 5.5、async/await 非同期が言語そのものに内蔵される
2023 Observation/SwiftData(iOS 17) SwiftUIが本番水準に到達し、重心が移る
2025 描画パイプラインの刷新(とされる) UIKitとの性能差がさらに縮んだと報告
2026 新規アプリの既定はSwiftUI UIKitは下の層へ回り始める

この表で自分が読み取るのは、勝ち負けではない。2008年の「もの」としての画面と、2019年の「関数」としての画面が、片方に一本化されるのではなく、層になって積み重なっているという事実だ。2026年のいま、SwiftUIの画面の下には、ほとんどの場合UIKitがいる。UIHostingControllerは、SwiftUIをUIKitの上に載せるための部品だ。新しい答えは、古い答えを消したのではなく、その上に乗った。

言い換えると、2026年の問いはもう「UIKitかSwiftUIか」の二択ではない。下にUIKit、上にSwiftUI、という層の重なりが既定になりつつある。問いは「どちらを選ぶか」から「どの層をどちらに任せるか」へ移った。このアプリは、たまたまその層が1枚しかないので、いちばん下のUIKitだけで足りている。層が増えた日には、上からSwiftUIが入ってくる。

歴史の続きは、どこへ向かうのか

予想を書いておく。この先、SwiftUIは吸収を続け、UIKitは「SwiftUIの下で画面を実際に出す層」へ静かに退いていく。アプリ開発者がUIKitを直接書く場面は減り続ける。だがゼロにはならない。少なくとも、起動の最初の数十ミリ秒を奪い合うような、いちばん下の層では残る。

このアプリ自身の続きも、たぶんそうなる。もし将来、設定や履歴といった「1画面では収まらない」部分が育ったら、そこはUIHostingControllerでSwiftUIを載せていく。新しい層の見返りが、その画面でだけコストを上回るからだ。だが、いちばん最初に出るキャプチャ画面——起動0.3秒の核——は、最後まで、あるいは永遠にUIKitのままかもしれない。歴史が「関数」へ進んでも、最下層で最初の0.3秒を守る仕事は、いちばん枯れた答えに任せたい。

最後に、自分が答えを持っていない問いを1つ置く。あなたがいま、ほぼ1画面の個人アプリを新しく始めるとして、最初の1行はUIKitとSwiftUI、どちらで書き始めるだろうか。そしてその選択を決めるのは、「最初の起動の速さ」だろうか、それとも「これから何年も面倒を見る前提での書きやすさ」だろうか。自分はこのアプリでは前者を取ったが、それは1画面という特殊な形だからだ。あなたの形では、たぶん答えが違う。その理由を、コメントで一言もらえると、次にどこかでSwiftUIへ寄せるときの、いい目印になる。


Obsidian連携シンプルメモ
外部ライブラリ依存ゼロ。UIKitとApple純正フレームワークだけで描いた、起動0.3秒のキャプチャ専用メモアプリ。
App Store:https://apps.apple.com/jp/app/captio%E5%BC%8F%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%83%A1%E3%83%A2/id6749649498

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?