Swiftで遊ぼう! on Hatena

あしたさぬきblogでやってた初心者オヤジのiOSプログラミング奮闘記がHatenaに来ました

Swiftで遊ぼう! - 1023 - EnvironmentObjectの取り扱い

新型コロナウイルス感染症アウトブレイクしてからというもの、乱れた生活が続いている。仕事柄、無用の外出をしないというスタンスを貫いているので、自宅と仕事場の往復だけのような生活が中心。根っからインドア派なので家に籠もる生活でもストレスを感じていないつもりだったが、馴染みの店には行きたいという衝動に駆られることもある。ニューノーマル時代の生活への変化に対応するためにやることも多く、忙しい日々を送っている。

好きで家に籠もっている生活なら、さぞプログラミングの勉強も捗っていると思うかもしれないが、鬱屈した平日の生活で溜まるストレス発散のため、週末はエンタメ動画を観ることが多いかもしれない。NetflixAmazonプライム、AppleTV+など、見たい動画も山ほどある。

自宅に籠もる生活と、新しもの好きの性格から、Appleシリコンの新しいMacは手に入れた。MacBook Pro M1 2020とXcode12.4が今の開発環境、いやいやまだ勉強環境か... いつになったら自分のアプリを発表できることやら。

なかなかアプリが公開できないのも私らしい展開なので、気長に付き合ってください。

昨年7月のエントリーで書いた記事で、EnvironmentObjectを何処でインスタンス化するか?なんて疑問を持っていました。

Swiftで遊ぼう! - 1019 - EnvironmentObject実装で疑問❓ - Swiftで遊ぼう! on Hatena

AppDelegate、もしくはSceneDelegateのどちらでインスタンス化したらいいか悩んでいたが、Xcodeがバージョンアップして、「12.4」では、何やら状況が変わってしまっていた。Swift開発環境の変化の速さに全くついて行けてない感は否めないが、食らいついていこう。

Xcode12.4で新規プロジェクトを作る際、オプションに「Life Cycle」が新設されていた。選択肢に「SwiftUI App」と「UIKit App Delegate」があり、「UIKit App Delegate」を選択すれば、今までと同じようにプロジェクトファイルに「AppDelegate」と「SceneDelegate」ファイルが存在する。しかし、デフォルトになっている「SwiftUI App」を選択すると、この2つのファイルが無くなる😩😱😩(←Touch Barから絵文字が便利に入力できるね)

SwiftUIを中心に据えて開発をするなら、やはりデフォルトの「SwiftUI App」を選択するしかないだろう。じゃあ何が違うのか、ちょっと調べて見ると、アプリの初期設定でマルチウインドウ対応かどうかのようんだ。プロジェクトのInfoをみると、「SwiftUI App」ではデフォルトで、「Enable Multiple Windows」が「Yes」になっている。開発ターゲットのプラットフォームにマルチウインドウシステムのMacOSとiPadOSがあるからだと思う。

f:id:yataiblue:20210215144040p:plain
Enable Multiple Windowsオプションは有効
「SwiftUI App」は、プログラミングの単純化を目指しているのだと思う。アプリ起動時の状態変化を読み込むために、複雑なコードが羅列する「AppleDelegate」と「SceneDelegate」の2つのファイルを利用するというのは、如何なことではないかとAppleも思ったのではないか。新登場したファイルは、「自分プロジェクト名App.swift」という名前が付いていて。中身をみると本当に単純な構造になっている。

import SwiftUI

@main
struct 自分のプロジェクト名App: App {

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

ここで、「@main」という枕詞と「Appプロトコールがあって、イマイチ理解できていない。でも、この単純なコードのみで、今まで長ったらしく書かれていた「AppDelegate」と「SceneDelegate」の代わりになっているということは、これら新しい呪文キーワードで包み隠したってことだろう。じゃあ、今までのSceneDelegateを利用して状態変化を感知するコーディング法の代わりは何か調べてみると、「Environmant型」で用意されていましたね。

import SwiftUI

@main
struct 自分のプロジェクト名App: App {
    @Environment(\.scenePhase) private var scenePhase

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: scenePhase) { phase in
            switch phase {
            case .active:
                print("scene is now active")
            case .inactive:
                print("scene is now inactive")
            case .background:
                print("scene is now in the background")
            @unknown default:
                print("Apple must have added something new")
            }
        }
    }
}

じゃあ最後に、Swiftで遊ぼう! - 1019 - EnvironmentObject実装で疑問❓ - Swiftで遊ぼう! on Hatenaの記事で疑問に思っていたEnvironmantObjectのインスタンス化をどこでするのか?そりゃズバリ、このAppプロトコールの中なんだ。本当に単純になっているよね。次のようにするだけ。

import SwiftUI

@main
struct EnvironmentObjectTestApp: App {
// このプロジェクトの名前に「EnvironmentObjectTest」と付けたから

    var appData = AppData()
    
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(appData)
        }
    }
}

どうです!このシンプルさ!まさにSwiftUIスタイルって言えるシンプルな実装法だ。もうUIKitプログラミングに戻れないかも。まだまだ勉強を続けるよ。