iOSやmacOSのバージョンが上がり、SwiftUIの機能も増えてきました。SwiftUIで作れる部分はSwiftUIを使い、UIKitと併用するということも徐々に出てきているのではないでしょうか?
この記事では、アプリのライフサイクルをUIKitからSwiftUIに変更する方法について解説します。
ビューを実装する
移行前のアプリは、Main.storyboardファイルがロードされて、ViewControllerクラスのビューが表示されるという構造になっています。このビューを表示する、SwiftUIのビューを実装します。
ContentView.swiftを追加し、次のコードを入力します。
import SwiftUI
struct ContentView: UIViewControllerRepresentable {
typealias UIViewControllerType = ViewController
func makeUIViewController(context: Context) -> ViewController {
// Main.storyboardをロードする
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// ViewControllerをインスタンス化
guard let viewController = storyboard.instantiateInitialViewController() as? ViewController else {
fatalError("Couldn't instanciate a ViewController class.")
}
return viewController
}
func updateUIViewController(_ uiViewController: ViewController, context: Context) {
}
}
UIKitのビューコントローラをSwiftUIのビューとして表示するには、UIViewControllerRepresentableを使います。ViewControllerを表示したいので、ViewControllerを表示するUIViewControllerRepresentableを継承したビューを実装しています。
この後の作業で、Main.storyboardはロードされないように変更するので、ContentView.makeUIViewController()メソッドで手動でロードしています。
SwiftUIのAppの適合タイプの追加
SwiftUIのAppの適合タイプを追加します。ここではSampleAppという名前にすることにしたので、SampleApp.swiftを追加し、次のようなコードを入力します。
// SampleApp.swift
import SwiftUI
@main
struct SampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
エントリーポイントの移行
アプリのエントリーポイントを、AppDelegate (UIApplicationDelegateの適合クラス)からSwiftUIのAppに移行します。
まず、AppDelegateの@mainを削除します。この記事では変更前の状態が分かるようにコメントアウトにしていますが、削除でOKです。
// AppDelegate.swift
import UIKit
// 削除する
//@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// ... 省略
}
Info.plistの編集
Info.plistを編集して、アプリ起動時にMain.storyboardを自動的に読み込まないように変更します。次のように操作します。
(1) ターゲットの設定を開き、「Info」タブを表示します。
(2) 「Main storyboard file base name」と「Principal class」(もし有ったら)を削除します。

(3) 「Application Scene Manifest」内の「Scene Configuration」を削除します。

AppDelegateのインスタンス化
AppDelegateでしか実装できない処理もあるので、AppDelegateが適切にSwiftUIのライフサイクルでも使われるようにします。それには、UIApplicationDelegateAdaptorを使用します。SampleApp.swiftに次のようにコードを追加します。
// SampleApp.swift
import SwiftUI
@main
struct SampleApp: App {
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
AppDelegateクラスのインスタンス化はSwiftUIによって行われます。インスタンスはEnvironmentObject経由で取得できます。そのためには、AppDelegateクラスがObservableObjectプロトコルに適合する必要があります。次のように、AppDelegate.swiftにコードを追加します。
// AppDelegate.swift
import UIKit
class AppDelegate: UIResponder, UIApplicationDelegate, ObservableObject {
// ... 省略
}
シーンの処理を変更
Info.plistの「Scene Configuration」を削除したので、AppDelegateの対応する部分の処理を変更します。次の2つのメソッドを削除します。アプリの都合で必要という場合には、動作を確認して残してください。
application(_:configurationForConnecting:options:)application(_:didDiscardSceneSessions:)
動作テスト
動作テストを行います。成功すると、Main.storyboard内のViewControllerのシーンが表示されます。

関連性が高い記事












