web-dev-qa-db-ja.com

iOS 13:Swift-「プログラムでアプリケーションルートビューコントローラを設定する」が機能しない

AppDelegate.Swiftに、iOSアプリケーションのルートビューコントローラーをセットアップする次のコードがあります。しかし、それは機能しません。ターゲット構造([全般]タブで定義)に従い、このコードは無視されます。

(Xcode 11、Swift 5.1、iOS 13)

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        window = UIWindow(frame: UIScreen.main.bounds)
        guard let rootVC = UIViewController() else {
            print("Root VC not found")
            return true
        }
        let rootNC = UINavigationController(rootViewController: rootVC)
        window?.rootViewController = rootNC
        window?.makeKeyAndVisible()

        return true
    }
}

問題がどこにあるのか理解できません。

私も参考文献を試してみましたが運はありませんでした:

28
Krunal

2つのオプションを試してみましたが、どちらもうまくいきました。 iOS-13(Xcode 11)では、UIWindowSceneのコンセプトを持つ新しいファイルSceneDelegate.Swiftがデフォルトで有効になっています。

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        guard let windowScene = (scene as? UIWindowScene) else { return }


        self.window = UIWindow(windowScene: windowScene)
        //self.window =  UIWindow(frame: UIScreen.main.bounds)

        let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
        guard let rootVC = storyboard?.instantiateViewController(identifier: "ViewControllerIdentifierName") as? ViewController else {
            print("ViewController not found")
            return
        }
        let rootNC = UINavigationController(rootViewController: rootVC)
        self.window?.rootViewController = rootNC
        self.window?.makeKeyAndVisible()
    }
}

代わりの:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        let windowScene = UIWindowScene(session: session, connectionOptions: connectionOptions)
        self.window = UIWindow(windowScene: windowScene)
        //self.window =  UIWindow(frame: UIScreen.main.bounds)
        let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
        guard let rootVC = storyboard?.instantiateViewController(identifier: "ViewControllerIdentifierName") as? ViewController else {
            print("ViewController not found")
            return
        }
        let rootNC = UINavigationController(rootViewController: rootVC)
        self.window?.rootViewController = rootNC
        self.window?.makeKeyAndVisible()

    }
}

なぜ、どのように機能するのかわかりませんが、問題は解決しました。

私を助けた参照ドキュメント:

28
Krunal

私は次のアプローチを試してみましたが、iOS 13ではそれが機能し、Xcode 11のiOS 12.4.2でもテストされました。

func resetRoot() {
            guard let rootVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController") as? ViewController else {
                return
            }
            let navigationController = UINavigationController(rootViewController: rootVC)

            UIApplication.shared.windows.first?.rootViewController = navigationController
            UIApplication.shared.windows.first?.makeKeyAndVisible()
     }
17

Xcode 11で作成されたプロジェクトから、SwiftUIでサポートされているアプローチに以前のアプローチを選択するには、次の手順に従います。

Steps for get old aproach

11
Carlos García

最初のケース

プロジェクトの大部分がストーリーボードでビルドされ、Xcode 11が開発に使用される前にSwiftUIを使用していない場合は、AppDelegateに関連付けられている古いクラスを使用する必要があります。

  • 次に、info.pllistの「アプリケーションシーンマニフェスト」を削除してみます。
  • プロジェクトからScenceDelegateを完全に削除します。

    その後、古いコードを使用できます。

2番目のケース

AppdelegteとScenceDelegateの両方を使用する場合は、以下のコードを使用します。

アプリ委任コード:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {   
 if #available(iOS 13.0, *){
    //do nothing we will have a code in SceneceDelegate for this 
} else {
    let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
    let VC = mainStoryboard.instantiateViewController(withIdentifier: "LoginVC") as! LoginVC
    navigationController?.isNavigationBarHidden = true
    navigationController = UINavigationController(rootViewController: VC)
    navigationController?.isNavigationBarHidden = true // or not, your choice.
    self.window = UIWindow(frame: UIScreen.main.bounds)
    self.window!.rootViewController = navigationController
}
return true
}

ScenceDelegateコード:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

    let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
    let VC = mainStoryboard.instantiateViewController(withIdentifier: "LoginVC") as! LoginVC
    navigationController?.isNavigationBarHidden = true
    guard let windowScene = (scene as? UIWindowScene) else { return }
    self.window = UIWindow(frame: windowScene.coordinateSpace.bounds)
    window.windowScene = windowScene
    window.rootViewController = VC
    window.makeKeyAndVisible()
    let appDelegate = UIapplication.shared.delegate as! AppDelegate
    appDelegate.window = window
}
7
Gurpreet Singh

IOS 13.xとiOS 12.x以下の両方で機能するものは次のとおりです

IOS 13の場合、シーンデリゲート

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
            guard let windowScene = (scene as? UIWindowScene) else { return }
            self.window = UIWindow(frame: windowScene.coordinateSpace.bounds)
           //Make sure to do this else you won't get 
           //the windowScene object using UIApplication.shared.connectedScenes
            self.window?.windowScene = windowScene 
            let storyBoard: UIStoryboard = UIStoryboard(name: storyBoardName, bundle: nil)
            window?.rootViewController = storyBoard.instantiateInitialViewController()
            window?.makeKeyAndVisible()
        }

ユーティリティクラスで、windowオブジェクトを取得してappdelegate.windowに割り当てる関数を以下に記述しました。必要に応じて、ウィンドウオブジェクトが必要なさまざまなシナリオの複数の場所にルートビューコントローラーを設定する必要がありました。

static func redirectToMainNavRVC(currentVC: UIViewController){
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let vc = UIStoryboard(name: appDelegate.storyBoardName, bundle: nil).instantiateViewController(withIdentifier: "MainNavigationViewController") as! MainNavigationViewController
    if #available(iOS 13.0, *){
        if let scene = UIApplication.shared.connectedScenes.first{
            guard let windowScene = (scene as? UIWindowScene) else { return }
            print(">>> windowScene: \(windowScene)")
            let window: UIWindow = UIWindow(frame: windowScene.coordinateSpace.bounds)
            window.windowScene = windowScene //Make sure to do this
            window.rootViewController = vc
            window.makeKeyAndVisible()
            appDelegate.window = window
        }
    } else {
        appDelegate.window?.rootViewController = vc
        appDelegate.window?.makeKeyAndVisible()
    }
}

これは私にはうまくいきました。うまくいけば、それは他の人にもうまくいきます。

3
Hemant Bavle
var window: UIWindow?

appdDelegate.SwiftからSceneDelegate.Swiftに移動されました。

だから私はScene DelegateクラスでrootViewControllerを使用し、それは機能します-

   func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        guard let _ = (scene as? UIWindowScene) else { return }

        if let tabBarController = window?.rootViewController as? UITabBarController {
                  let storyboard = UIStoryboard(name: "Main", bundle: nil)
                  let vc = storyboard.instantiateViewController(identifier: "NavController")

                  vc.tabBarItem = UITabBarItem(tabBarSystemItem: .topRated, tag: 1)
                  tabBarController.viewControllers?.append(vc)
              }
    }
3
Aditya Ahuja

私は二つのことをしました。最初にNotificationSceneDelegateに設定し、次にRootViewControllerを変更する必要があるときにNotification Postそしてそれは働いた。しかし、それはひどい解決策です。

その後

上司から、ControllersNavigationControllerを次のように変更するよう勧められました。

func logged() {
    let mainStoryboard: UIStoryboard = UIStoryboard(name: "MainTabViewController", bundle: nil)
    let mainVC = mainStoryboard.instantiateInitialViewController()

    self.navigationController?.setViewControllers([mainVC!], animated: false)
}

おそらくそれが最善の解決策ではないことは知っていますが、私はそれがよりクリーンであると思います。
私は現在iOS 13で作業しており、deprecatedを使用したくありませんでした。

0
unferna