application(_ :configurationForConnecting :options: )メソッドについて調べたことのまとめ

application(_:configurationForConnecting:options:)について、調べたことを備忘録としてまとめておきます。
2019.10.21

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

大阪オフィスの山田です。最近、松茸を500円で買ったので、松茸ご飯を作りました。美味しかったです。 application(_:configurationForConnecting:options:)について、調べたことを備忘録としてまとめておきます。この記事を書いている際に、参考にさせていただいた記事や公式のドキュメントは、この記事の参考セクションに全てまとめてあります。

開発環境

  • Xcode11.1(11A1027)
  • macOS10.14.6

調べたことと検証結果

Xcode11.1で新規にプロジェクトを作るとAppDelegate.swiftとSceneDelegate.swiftが追加されていると思います。AppDelegate.swiftの以下のコードに着目します。iOS13から使えるメソッドです。

func application(_ application: UIApplication, 
    configurationForConnecting connectingSceneSession: UISceneSession, 
    options: UIScene.ConnectionOptions
) -> UISceneConfiguration

このメソッドはSceneが作成される時に、UIKitのための設定を行います。 自動でこのメソッドは作成されますが、実装しなければInfo.plistに定義された設定内容の0番目が、設定に使用されるようです。この設定には、作成するSceneのタイプ、Sceneを管理するオブジェクト、最初に表示するViewControllerを含むStoryboardの情報が含まれます。

このメソッド内で、Info.plistに作成した設定をConfiguration Nameで指定して、出しわけすることが可能です。試してみます。まず、以下のように設定を2つ作っておきます。 plist

Default ConfigurationはMain.storyboard、Second ConfigurationはTest.storyboardを設定しています。

続いて、AppDelegate.swiftで以下のように実装します。

// パターン1
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    let config = UISceneConfiguration(name: "Second Configuration", sessionRole: connectingSceneSession.role)
    return config
}

下の方に画面のスクリーンショットを貼っていますが、Second Configurationに定義されているTest.storyboardが読み込まれ、initial viewcontrollerが表示されています。

次のパターンでは、Second Configurationを読み込んだ後、configのstoryboardに別途設定しています。

// パターン2
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    let config = UISceneConfiguration(name: "Second Configuration", sessionRole: connectingSceneSession.role)
    config.storyboard = UIStoryboard(name: "Hoge", bundle: .main)
    return config
}

そうすると、Hoge.storyboardが読み込まれ、initial viewcontrollerが表示されます。

前述の通り、このメソッド自体をコメントアウト、あるいは削除するとInfo.plistに記載されている内容の0番を使って設定が行われました。

//    パターン3
//    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
//        let config = UISceneConfiguration(name: "Second Configuration", sessionRole: connectingSceneSession.role)
//        config.storyboard = UIStoryboard(name: "Hoge", bundle: .main)
//        return config
//    }
パターン1 パターン2 パターン3
Simulator Screen Shot - iPhone 11 - 2019-10-18 at 14.14.24.png Simulator Screen Shot - iPhone 11 - 2019-10-18 at 14.15.11.png Simulator Screen Shot - iPhone 11 - 2019-10-18 at 14.13.52.png

configを取得する際のsessionRoleについて

sessionRole: connectingSceneSession.role

引数に使われている上記の値ですが、実際にrawValueを見てみると、UIWindowSceneSessionRoleApplication という値が入っていました。これを検索するとInfo.plistのキー値となっています。Info.plistにもう一度着目すると、Scene Configurationの下に、External Display Session Roleを追加することが可能となっています。外部ディスププレイセッションが発生した時に、SceneDelegateを切り替えることが可能なように見えます。(筆者は外部ディスプレイを使うアプリを作ったことがないので、この部分は想像です)

configに設定できるdelegateClassについて

以下のようにdelegateClassを指定することで、使用するSceneDelegateのクラスを指定することができます。Info.plistにて指定することも可能です。 この例ではSecondSceneDelegateクラスを作成し、プログラムから指定しています。

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    let config = UISceneConfiguration(name: "Second Configuration", sessionRole: connectingSceneSession.role)
    config.delegateClass = SecondSceneDelegate.self  <- delegateClassの指定
    return config
}
class SecondSceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let _ = (scene as? UIWindowScene) else { return }
    }
}

なので、application(_:configurationForConnecting:options:) メソッドの中で条件によってどのSceneDelegateを使うかを選択することができます。プロパティのDiscussionを見ると、後述するsceneClassがUIWindowSceneクラスである場合は、UIWindowSceneDelegateに適合したクラスを指定する必要があります。そうでなければUISceneDelegateに適合したクラスを指定することが可能とのことです。

configに設定できるsceneClassについて

UIKitが作成するSceneオブジェクトのクラスを指定することができます。UISceneあるいはそのサブクラスを指定することができます。実際にSceneDelegate.swiftの中でUIWindowSceneサブクラスが使われています。プロパティのDiscussionの内容を見ると、通常このUIWindowSceneクラスを使うようで、考えてみたものの、他のクラスを使うケースが思いつきませんでした。こちらもInfo.plistに記述することが可能です。

参考

最後に

SceneDelegateも含めて調べてるうちに「iPad欲しいな」ってなりました。