下記ブログの転載です!
https://rc-code.info/ios/post-293/
SwiftUI
をいじっていて、初回起動時の画面設定の仕方が今までと異なっていたので、ざっと紹介します。
SwiftUI
を利用するか否かに限らず、アプリのUIを複数インスタンスで管理する方法(すなわち複数画面を単体アプリで管理する事と同意)を提供するために、Xcode11
から UIScene
という概念が導入されましたので、そのことに少し触れようと思います。
詳細は こちら 。
今までの設定方法
今までは AppDelegate
の didFinishLaunchingWithOptions
内で window
を生成する、もしくは Deployment Info
の Main Interface
にて設定するのが一般的でした。
⬇️AppDelegate didFinishLaunchingWithOptions の例
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self
window = UIWindow(frame: UIScreen.main.bounds)
if let vc = UIStoryboard.init(name: "Main", bundle: nil).instantiateInitialViewController() {
let navigationVc = UINavigationController(rootViewController: vc)
self.window?.rootViewController = navigationVc
}
}
以下省略
}
新しい初期画面の設定方法
Xcode11
導入後は UIWindowSceneDelegate
を利用した下記の方法が推奨されるようです。
1. UISceneConfiguration の設定
まず、AppDelegate
に新しく追加された configurationForConnecting
関数にて、UISceneConfiguration
として設定する対象を明記します。
class AppDelegate: UIResponder, UIApplicationDelegate {
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
他省略
}
上記で設定した Default Configuration
は Info.plist
の Application Scene Manifest
に記載された Scene Configuration > Application Session Role > Item0
が当て込まれます。
下記が Info.plist
の画像です。
この Item0
内で Configuration Name
を Default Configuration
に設定しているので、上記のコードを記載した時にこの Item0
が UISceneConfiguration
として呼び出されるわけです。
Item0
には LaunchStoryboard Name
という項目もあり、名前の通りここに記載した名前の Storyboard
が 起動時の画面として呼び出されます。
また、Delegate Class Name
に指定した名前のクラスが SceneDelegate (UIWindowSceneDelegate)
として利用されます。
2. UIWindowSceneDelegate の設定
SceneDelegate
では、今まで AppDelegate
の didFinishLaunchingWithOptions
関数で指定していたように、window
への割り当てができます。
そうです。
UIApplicationDelegate
同様、UIWindowSceneDelegate
も window
のオプショナル定義を持っているのですw
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let window = UIWindow(frame: UIScreen.main.bounds)
window.rootViewController = UIHostingController(rootView: ContentView())
self.window = window
window.makeKeyAndVisible()
}
以下省略
}
上記の ContentView
は SwiftUI
の View
プロトコルを満たした構造体です。
UIHostingController
は描画のライフサイクルを担当する、いわば UIViewController
の Controller
部分だけを抽出し SwiftUI
に合わせた感じのクラスのようです。(ざっくりとしか見てないので雑ですいませんw)
上記の例では、この UIHostingController
を window
の rootViewController
として格納しています。
さて、これで ContentView
がメインの View
構造体として設定されたので、あとはこの中身をゴリゴリと変えてく、ということになります。
ちなみに、ここまで説明してきた諸々の設定は、プロジェクト作成時に SwiftUI
項目にチェックを入れて開始するとデフォルトで入っています。
つまり、SwiftUI
ではこの駆動方法が一般的ということになりそうですね!
今までのやり方はダメなの!?
冒頭に記載した今まで通りの初期画面設定ですが、Xcode11
でも UIApplicationDelegate
プロトコルから var window
のオプショナル定義は削除されておらず、引き続きこちらでも駆動はできるようです。
Main Interface
の指定枠も同様です。
ですが、UIApplicationDelegate
が端末とアプリケーションを繋ぐためのデリゲートを担当し、アプリの複数画面描画(とりわけ window
や Scene
)を SceneDelegate
が担うという構造になっていきそうな予感はプンプンしますね。
そのうち AppDelegate
から window
関連の制約が deprecated
になる気がします。
思っちゃったこと
Xcode11
から Window
や Scene
を管理するための機構が多く見られます。
個人的な見解ですが、これは「個人が発信する」という文化にアプリケーションをマッチさせるための布石のように思います。
今回(2019/6 現在)の WWDC
での発表を見ると、iPad
を利用したプログラミング開発を斡旋するような機能や、PC
と連動させて iPad
を活用するような試みが見られます。
これは比較的大きな端末サイズに民衆を慣れさせることに成功した Apple
が、次はその端末でもう少し上位の体験を簡単に実行できるようにするフェーズに入ったことの証明の様に感じます。
iPadOS
だけではなく iOS
でも同様の動きを取っていくでしょう。
現状、私たちは動画をアップする際、まずカメラで撮影し、編集し、それをSNSにアップロードします。コメントが来ればコメント欄を開き、いいねを押されればその人の画面に遷移してお返しをします。
これをシームレスに単体の端末内で実行できるとすれば、多くの民衆、もしくはプロのカメラマンや動画プロデューサーでさえ、その端末を利用するでしょう。
画面内に「カメラ自体のキャプチャ、編集枠、配信中の画像(編集を加えたキャプチャ)、コメント欄、Info枠...etc」などが混在し、それを直感的に掌の中で実行できる様になることを目指しているのではないでしょうか?
そのための布石としての UIWindowSceneDelegate
である気がします。
そのうち、リジェクトの内容で
「ここのコメント画面は動画を見ながら確認できる様に別シーンで管理してくれたまえよ」
といった内容も出てくるのではなかろうかと。