「SwiftUI にすべきか、React Native にすべきか」——個人開発でiOSアプリを作る際に必ず直面するこの問いに、私は長年「ケースバイケース」と答えてきました。しかしそれは正直に言うと、自分でも確信が持てなかったからです。
そこで2026年の初めに一つの実験をしました。まったく同じ仕様のアプリを Rork Max を使って SwiftUI と React Native の両方で実装し、開発速度・コード量・実行時パフォーマンス・長期的な保守性を比較したのです。このレポートは、その実験の記録です。
実験の設計:同じ仕様、異なるスタック
比較対象のアプリは「壁紙コレクションアプリ」です。個人的に長く運用しているジャンルで、要件を自分でコントロールできます。
実装する機能は次の通りです:
- 壁紙一覧(無限スクロール・カテゴリフィルタ)
- 壁紙詳細(フルスクリーン表示・保存機能)
- お気に入り管理(永続化あり)
- サブスクリプション(RevenueCat 連携)
- プッシュ通知(Firebase)
この仕様を、同じ期間(各2週間)、同じ Rork Max のセッション数(1日2〜3セッション)で実装しました。
SwiftUI 実装:Rork Max との相性
SwiftUI 実装から着手しました。Rork Max の SwiftUI サポートは、率直に言って「かなり良い」状態でした。
List や LazyVGrid を使った一覧表示は、要件を伝えるだけでほぼ完成形のコードが出てきます。
// Rork Max に「カテゴリフィルタ付きの壁紙グリッドを実装して」と伝えると
// 以下のようなコードが生成される(一部省略)
struct WallpaperGridView: View {
@StateObject private var viewModel = WallpaperGridViewModel()
@State private var selectedCategory: WallpaperCategory = .all
let columns = [
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible())
]
var body: some View {
NavigationStack {
ScrollView {
CategoryFilterBar(selected: $selectedCategory)
.onChange(of: selectedCategory) { _, newValue in
viewModel.filter(by: newValue)
}
LazyVGrid(columns: columns, spacing: 2) {
ForEach(viewModel.wallpapers) { wallpaper in
WallpaperThumbnail(wallpaper: wallpaper)
.onAppear {
viewModel.loadMoreIfNeeded(current: wallpaper)
}
}
}
}
}
}
}このコードが1回のプロンプトで出てきた点は印象的でした。ただし、いくつかの問題もありました。
問題1:SwiftConcurrency の使い方が古い。Rork Max が生成するコードは async/await を使っていますが、@MainActor の付与方法が古いパターンであることがありました。DispatchQueue.main.async 時代の書き方が混在するケースがあり、修正が必要でした。
問題2:StoreKit 2 の対応が不完全。RevenueCat 連携は問題なく動きましたが、StoreKit 2 をネイティブに使う実装を依頼すると、StoreKit 1 と 2 の混在したコードが出てくることがありました。DECISIONS.md に「RevenueCat 経由のみ使用、StoreKit 直接は禁止」と明記することで解決しました。
2週間での完成度:機能実装 95%・テスト 70%
React Native 実装:Rork Max との相性
React Native 実装では、まず Expo Router v3 をベースにしました。Rork Max の React Native サポートは SwiftUI と比べると、ライブラリの多様性ゆえに「どのライブラリを使うか」の指定が重要でした。
指定なしで「壁紙グリッドを実装して」と依頼すると、FlatList を使う実装・FlashList を使う実装・独自の ScrollView ラッパーを使う実装がセッションによってバラバラに出てきました。
// .agents.md に明記した制約(一部)
// リスト表示: @shopify/flash-list を使用(FlatListは禁止)
// ナビゲーション: expo-router v3 のみ(react-navigationは禁止)
// 状態管理: Zustand(Redux禁止)
// スタイリング: NativeWind v4(StyleSheet禁止)この制約を明記してから、生成されるコードの一貫性が大幅に改善しました。
React Native 固有の良い点として感じたのは、「ロジックのテスト書きやすさ」です。ビジネスロジックが純粋なTypeScriptで書かれるため、Jest でのユニットテストが SwiftUI より書きやすかった。お気に入り管理のロジックテストは1セッションで完成しました。
問題1:ネイティブモジュールの設定。Firebase プッシュ通知の設定で、google-services.json の配置と app.json の設定が同期していないエラーが発生しました。Rork Max はこの問題を自力で解決できず、公式ドキュメントを参照しながら手動で解決しました。
問題2:パフォーマンスチューニングの限界。100枚以上の画像をスクロールするとフレームレートが落ちる問題を Rork Max に相談すると、memo のラップ・shouldComponentUpdate の代替・useCallback の追加など、複数の提案が出ましたが根本的な解決には至りませんでした。最終的に FlashList への完全移行と FastImage の導入で解決しましたが、この判断は自分で行う必要がありました。
2週間での完成度:機能実装 90%・テスト 75%
比較結果:6つの指標で評価
両方の実装を終えて、6つの指標で比較しました。
開発速度:SwiftUI がやや速い(同じ機能を SwiftUI で1.5時間 vs React Native で2時間)。Rork Max の SwiftUI 理解度が高く、1回のプロンプトで完成度の高いコードが出やすかった。
コード量:React Native がやや少ない(SwiftUI 約2,800行 vs React Native 約2,100行)。型とUI記述の冗長さが Swift 側を増やしています。
起動速度(実機):SwiftUI が明確に速い(初回起動 SwiftUI 0.8秒 vs React Native 1.4秒)。冷起動の差は体感でもわかる。
スクロールパフォーマンス:SwiftUI のほうが滑らか。React Native は FlashList 使用でかなり改善されるが、SwiftUI LazyVGrid のほうが細かい最適化が自動で効いている印象。
保守性:ほぼ同等だが、型安全性の観点では SwiftUI + Swift の組み合わせがわずかに優位。TypeScript も型安全だが、React Native のエコシステムには型定義が不完全なライブラリが多い。
将来性・Android展開:React Native が明確に有利。同じコードベースで Android 対応できるメリットは、個人開発では非常に大きい。
どちらを選ぶべきか:シナリオ別の結論
この実験を通じて、「ケースバイケース」という答えが正しかったことを改めて確認しましたが、より具体的な判断基準が得られました。
SwiftUI を選ぶべきシナリオ:iOS 専用・パフォーマンスが最重要・Apple 標準機能(WidgetKit・Live Activities・WatchKit)を深く活用したい・チームが Swift に習熟しています。
React Native を選ぶべきシナリオ:iOS + Android 両対応・チームが TypeScript に習熟している・Web サービスとのコード共有が必要・長期的なクロスプラットフォーム展開を想定しています。
私の個人開発では、今後は次の方針で使い分けることにしました:「Apple 標準機能を活かした差別化ができるアプリ → SwiftUI」「マルチプラットフォーム展開が前提のアプリ → React Native」。
Rork Max は、どちらを選んでも開発速度を大きく向上させてくれます。ただし、最も恩恵を受けるのは「プロジェクトの制約を .agents.md に明記してから使い始めた場合」です。この準備を省くと、生成コードの一貫性が落ちて、その修正に余計な時間を使うことになります。
Rork Max を最大限活用するための最初のステップは、AIに何を作らせるかの前に、「どのスタックで・どのルールで作るか」を自分の中で決めることだと感じています。