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
}
}
問題がどこにあるのか理解できません。
私も参考文献を試してみましたが運はありませんでした:
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()
}
}
なぜ、どのように機能するのかわかりませんが、問題は解決しました。
私を助けた参照ドキュメント:
私は次のアプローチを試してみましたが、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()
}
最初のケース
プロジェクトの大部分がストーリーボードでビルドされ、Xcode 11が開発に使用される前にSwiftUIを使用していない場合は、AppDelegateに関連付けられている古いクラスを使用する必要があります。
プロジェクトから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
}
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()
}
}
これは私にはうまくいきました。うまくいけば、それは他の人にもうまくいきます。
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)
}
}
私は二つのことをしました。最初にNotification
をSceneDelegate
に設定し、次にRootViewController
を変更する必要があるときにNotification Post
そしてそれは働いた。しかし、それはひどい解決策です。
上司から、Controllers
のNavigationController
を次のように変更するよう勧められました。
func logged() {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "MainTabViewController", bundle: nil)
let mainVC = mainStoryboard.instantiateInitialViewController()
self.navigationController?.setViewControllers([mainVC!], animated: false)
}
おそらくそれが最善の解決策ではないことは知っていますが、私はそれがよりクリーンであると思います。
私は現在iOS 13で作業しており、deprecated
を使用したくありませんでした。