UIKitからSwiftUIへの移行の第一歩を踏み出してみた

2022.02.07

プロジェクトを新規作成する時には、オプション設定時にライフサイクルをSwiftUIに設定するとXcodeがいい感じに初期設定してくれるのですが、ライフサイクルをStroyboardに設定して作った既存プロジェクトをSwiftUIに移行する方法を実際に試しながらまとめてみました。

はじめに

  • 今回はSwiftUIに関する話はほとんどしていません。
  • 試したアプリもテキストを描画しているだけのシンプルなもの。
  • UIKitからSwiftUIへの移行の第一歩の部分の話になります。

環境

  • Xcode 13.2.1

移行前のアプリ

デモ

アプリの画面にはテキストが表示されているだけのシンプルなアプリになります。

Main.storyboard

Main.stroyboardに"Good bye UIKit"というテキストのUILabelを配置しています。

Launch.storyboard

Assets.xcassetsにgoodbyeという画像ファイルを追加しており、そのイメージを表示するようにしています。

それでは移行していきましょう!

1. AppDelegateから@mainを削除する

AppDelegate.swiftから@mainまたは@UIApplicationMainを削除する 

削除前

//  AppDelegate.swift

import UIKit

@main // ←@mainを削除
class AppDelegate: UIResponder, UIApplicationDelegate {

削除後

//  AppDelegate.swift

import UIKit

class AppDelegate: UIResponder, UIApplicationDelegate {

@mainとは

こちらのmain-attribute.mdの引用すると、

A Swift language feature for designating a type as the entry point for beginning program execution. Instead of writing top-level code, users can use the @main attribute on a single type. Libraries and frameworks can then provide custom entry-point behavior through protocols or class inheritance.

簡単にいうと、@main属性を付与することでプログラムを実行する為のエントリーポイントとしてタイプを指定することのできるSwiftの機能になります。

2. SwiftUIのAppを追加

New File...Swift FileまたはSwiftUI Viewを新規で追加。今回はファイル名をGoodByeUIKitAppとします。

新規で追加したファイルの内容をSwiftUIで用いるAppの内容を記述します。

import SwiftUI

@main
struct GoodByeUIKitApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    var body: some Scene {
        WindowGroup {
            ContentView() // 一番最初に表示されるView: これから作成します
        }
    }
}

Appに記載にあるように、構造体の宣言の前に@mainを付けて、アプリへのエントリポイントを提供することを示しています。 Sceneプロトコルに準拠するインスタンスからアプリの本体を作成しています。

@UIApplicationDelegateAdaptorを使用することで既存のAppDelegateにアクセスすることができる。といっても、今回のサンプルアプリでは使用していないので消しても良かったりする。

3. ContentViewの作成

アプリが開かれた際に一番最初に表示されるViewを作成します。

New File...SwiftUI Viewを新規で追加。今回はファイル名をContentViewとします。実際に使用する際はその場に適した命名にしていただけたらと思います。

// ContentView.swift

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello SwiftUI.")
            .font(.title)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

@mainも変更したし、最初に表示するViewも作成したのでシュミレーターで実行してみましょう。

SwiftUIへの移行ができていたら、Hello SwiftUI.のテキストが表示されるはずですが、まだ移行できていないようです。

移行する為には、Info.plistの変更が必要になります。

4. Info.plistを変更する

TARGETS > Info から Custom iOS Target Propertiesの中を変更していきます。

不要なものを削除

Storyboardを使わなくなるので、その周辺のプロパティを消していきます。

  • Main storyboard file base name
  • Storyboard Name

上記2つのKeyは削除します。

  • Enable Multiple Windows

こちらのKeyの値をYESに変更しておきます。

Multiple Windows

iPadで使用出来る1つのアプリで複数のウィンドウを開ける機能です。

今回は特に使用していない機能なのですが、アプリをビルドする際にこの値がYESになっていないと画面が真っ黒に表示される為、一度YESに切り替えておきます。もし、不要であれば画面が表示されたのを確認後、NOに変更していただければと思います。

動作確認

ここまで来たら、Main.storyboardも不要なので名残惜しいと思いますが削除します。

それでは、シュミレーターで実行してみましょう。

無事にSwiftUIで作成した画面が表示されました!

5. Launch.storyboardの削除

現段階では、Launch.storyboardに特に変更を加えておらず、そのまま使用出来ています。このまま使用しても問題はないのですが、せっかくなのでLaunch.storyboardを削除して、Info.plistのLaunch Screenで対応していきます。

不要なものを削除

TARGETS > Info から Custom iOS Target Properties

  • Launch screen interface file base name

このKeyは削除します。

またLaunch.storyboardも不要な為削除します。

Launch Screenを追加する

Info.plistにLaunch Screenを追加します。

Launch ScreenはDictonary型になっており、その値を設定することでLaunch画面を作成することが出来ます。作成時には、Image Nameというものが自動で追加されており、こちらのValueにはAssetsで定義している画像ファイルの名前を設定することで表示することが出来ます。今回はgoodbyeというファイル名のものをそのまま使用しました。

Image Name以外にも、

  • Background color 背景色
  • Image respects safe area insets 画像のセーフエリア設定
  • Show Navigation bar ナビゲーションバーの表示
  • Show Tab bar タブバーの表示
  • Show Toolbar ツールバーの表示

こちらの設定もすることが出来ます。

最終デモ

ここまで来たら、プロジェクトからStroyboardは全て無くなりました。実際に動作するか動きを見てみましょう。

無事にUIKitからSwiftUIに移行することが出来ました!

おわりに

名残惜しいですが、Storyboardとお別れしました。

これからの時代はスケートボードです。みんなでスケートボードしましょう!

参考