🐦

SwiftUI時代のホットリロードについて

2024/11/26に公開

記事の背景

SwiftUIを使用したホットリロードを正しく説明した記事がほとんどないため備忘録を残しておきます。

結論を先に

1, hotreloadingパッケージとhotswiftUIパッケージをプロジェクトに追加する

2, Build Settingsから"Other Linker Flags" > "Debug"を選択して"-Xlinker -interposable"を追加する

3, 画面上部のアプリ名をクリックしEdit Shcemaから環境変数に"INJECTION_STANDALONE"を追加する。

4, アプリのエントリーファイルに"#if DEBUG ~~~"のコードと".eraseToAnyView"を追加する。

import SwiftUI
@_exported import HotSwiftUI

@main
struct MainApp: App {
    #if DEBUG
    @ObservedObject var iO = injectionObserver
    #endif
    var body: some Scene {
        WindowGroup {
            ContentView()
                .eraseToAnyView()
        }
    }
}

※新しいViewを追加する時には必ず以下のコードを追加してください。hotreloadingとswiftUIは
@ObservedObjectを監視して変更を反映しています。".eraseToAnyView()"の記述はエントリーポイントに対して一つだけの設定で問題ありません。 こちら勘違いでした。これでもかというくらい全てのViewに".eraseToAnyView"をつけてください。

    struct SubView: View {
    #if DEBUG
    @ObservedObject var iO = injectionObserver
    #endif
    var body: some Scene {
        VStack {---}
            .eraseToAnyView()
    }
    }

5, 下記画像のように"InjectionClient/Could not connect~~~"のエラーが出ますが、動作には影響ありません。

よくある勘違い

  • InjectionIIIアプリとhotReloadingパッケージを併用する必要はありません。HotSwiftUIはどちらか一つが存在すれば機能します。(ただしhotReloadingパッケージを使用する場合はストアへのアップロード時にパッケージを削除する必要があります。)
  • InjectionIIIアプリとInjectパッケージはUIKit時代のホットリロード手法らしいです。(一応SwiftUIでも動作しますが、型の変更を伴うようなコードの変更を加えると例外が発生して再リロードが必要になります。)

参考

https://github.com/johnno1962/HotSwiftUI
https://github.com/johnno1962/HotReloading

最後に

間違いや勘違いが記事の中に含まれていたら、ご教授いただけるとありがたいです!
動く状態になるだけで100%正しい使い方をしている確信はないです!

Discussion