15
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

iOSAdvent Calendar 2021

Day 1

新規プロジェクト作成せずに、既存プロジェクトをUIKitからSwiftUIに移行するまでにやったこと

Posted at

概要

既存UIKitプロジェクトをSwiftUIに移行する機会がありました。

UIKitからSwiftUIへの移行の仕方で調べると、新規でプロジェクトを作成することでの移行のやり方、つまりSwiftUIをUIフレームワークに指定してプロジェクトを新規作成するやり方しかヒットしなかったので、
既存のUIKitプロジェクトを移行することはできないのかと勝手に思い込んでました。

でも、SwiftUIで作成されたプロジェクトを見ると、別に新規でプロジェクト作成しなければいけなそうな理由はなかったので(例えば新規作成したときにしか作成されない必須ファイルがあるとか)、試してみたところ普通にできました・・・

既存のUIKitを使ったプロジェクトをSwiftUIに移行するということ自体、頻繁に発生しないかもしれないですが、今後の自分や誰かのために残しておきます。

ちなみになぜ自分はこれをやりたかったのかというと、訳あってGitの履歴を途切れさせずに、UIKitからSwiftUIへ移行したかったからです。

環境

  • Xcode13.0

やってみた

何か正式な手順を踏んでやったというよりかは、UIKitとSwiftUIのプロジェクトを見比べて、SwiftUI側のプロジェクトにあるファイルや設定をUIKitを使ったプロジェクトの方に移していっただけではあります。
なので、順番はあまり意識していません。

実際に移行作業をした時は試行錯誤しながらだったので、今回記事を書くに当たってもう一度やってみることにしました。

ちなみにここで書くのは、SwiftUIのライフサイクルプロジェクトへの移行です。

1. エントリポイント周りの修正

周りくどいと思いますが、まずAppDelegate.swiftにある@mainをコメントアウトしてみました。
AppDelegate.swiftにある@mainはエントリポイントを示しているため、これがないと動かないはずですよね。
やってみたところ、想定通りビルドエラーが出ました。
Entry point (_main) undefined. for architecture x86_64とのこと。

スクリーンショット 2021-12-29 17.31.20.png

では早速、エントリポイントを決めるため、別のSwiftUIファイルを作成します。
デフォルトだと、こんな感じの中身になるので、

import SwiftUI

struct UIFrameworkMigrationTestApp: View {
    var body: some View {
        Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
    }
}

struct UIFrameworkMigrationTestApp_Previews: PreviewProvider {
    static var previews: some View {
        UIFrameworkMigrationTestApp()
    }
}

それをこっち↓に差し替えます。
ライフサイクルをSwiftUIに設定して新規プロジェクト作成したのであれば、勝手に作成されるファイルですが、今回は移行元プロジェクトはUIKitで作成していたので、このファイルは自分で作成します。

import SwiftUI

@main  // アプリのエントリ
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView() // 最初に表示される View
        }
    }
}

あとはContentView()を作成して適当に作りたいViewを実装します。

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("SwiftUIに移行したよ")
    }
}

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

これでビルドをしてみたところ、ビルドエラーはなくなりました。
が、ContentViewで実装した「SwiftUIに移行したよ」は表示されておらず、最初に作ったときのstoryboardの画面が表示されています。

どうやらアプリ起動時の画面がまだstoryboardのままのようです。

2. Info.plistを変更する

いじったのは4つです。

やったことしては、storyboardは使わないようになるので、それ周りの設定を削除したことと
Enable Multiple Windowsをいじったこと
です。

  • Launch screen interface file base nameを削除

スプラッシュ画面が表示されなくなり、スプラッシュ画面以降の最初の画面が表示されます。でもまだSwiftUIで実装したViewは表示されません。storyboardの方が表示されています。

  • Main storyboard file base nameを削除
  • Storyboard Name(Application Scene Manifest > Scene Configuration > Application Session Role > item 0 の中)を削除

ビルドしてみると、ビルドエラーは出ませんが、画面が真っ黒になります。

  • Enable Multiple WindowsYESに変更

理由はわからなかったのですが、これを一度YESに書き換えてビルドすると、SwiftUIで実装したViewがちゃんと表示されるようになります。
ただ、これをまたNOに戻しても、問題なく表示されてはいましたので、NOに戻しました。

なぜ一旦YESにしないといけないのでしょう・・・わからないのですが、真っ黒なまま表示されなくて悩んでいたところ、こちらの記事に以下の記述があったので、やってみたところ、表示されるようになりました。

UIApplicationSupportsMultipleScenes がもともと false で、ライフサイクル変更と共に true にして上書きインストールすると、上記の現象は起きなかった。

最終的にこうなりました。↓
スクリーンショット 2021-12-29 18.02.36.png

参考

終わりに

意外と、移行作業でやったことは多くなかったみたいです。
あとは、storyboardで実装していたところをSwiftUIで書き直したりといったことですね。

AppDelegate.swiftやSceneDelegate.swiftを使用しないのであれば、削除してしまっても良いと思います。実際私が移行作業をした時は、特に必要なかったので削除しました。

ただし、現状ではAppDelegateがないと実装できないこともあるようなので、場合によって必要有無は変わりそうです。
参考に載せたリンクにもあるように、SwiftUIライフサイクルでプロジェクトを作成していてもAppDelegateが必要になって後から追加する例もあります。

最後になりますが、上記に記載した作業ログとして、Gitのコミットに履歴を残しました。

Enable Multiple Windowsをいじる必要があるのは何故か分かったら、更新しようと思います。

ViewのコードがついにHuman Readableになって幸せになれそうです。

未来の私の役に立てばいいな。

15
10
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
15
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?