在AppDelegate中设置初始视图控制器 - Swift

174

我想从appdelegate设置初始的视图控制器。我找到了一个非常好的答案,但是它是用Objective C编写的,我在Swift中尝试实现同样的内容时遇到了困难。

使用故事板编程设置初始视图控制器

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];

    UIViewController *viewController = // determine the initial view controller here and instantiate   it with [storyboard instantiateViewControllerWithIdentifier:<storyboard id>];

    self.window.rootViewController = viewController;
    [self.window makeKeyAndVisible];

    return YES;
}

有人能帮忙吗?

我想让初始视图控制器依赖于某些条件,使用条件语句来实现。


这可能是一个重复的问题:https://dev59.com/8Wkv5IYBdhLWcg3wsCpO#14926009 - mfaani
25个回答

301

Xcode11 和 SceneDelegate 注意事项:

从Xcode11开始,由于SceneDelegates的存在,你不应该在AppDelegate中处理此事。相反,应该从SceneDelegate中处理。更多信息请参见这个回答


旧的回答:

我使用了这个线程来帮助我将Objective C转换为Swift,而且它完美地运行。

在Swift中实例化和呈现viewController

Swift 2 代码:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
    
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    
    let initialViewController = storyboard.instantiateViewControllerWithIdentifier("LoginSignupVC")
    
    self.window?.rootViewController = initialViewController
    self.window?.makeKeyAndVisible()
    
    return true
}

Swift 3代码:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    self.window = UIWindow(frame: UIScreen.main.bounds)

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    
    let initialViewController = storyboard.instantiateViewController(withIdentifier: "LoginSignupVC")

    self.window?.rootViewController = initialViewController
    self.window?.makeKeyAndVisible()

    return true
}

1
在 Swift 2 应用程序中找不到故事板 "Main" 或 "Storyboard.storyboard"。 - Async-
5
这是在appdelegate中设置初始视图控制器的当前标准方式吗?我问这个问题是因为它看起来有点像一种 hack(抱歉@Abs)。 - rigdonmr
12
如果应用程序有一个作为主界面的Storyboard,窗口将自动加载,并将其根视图控制器设置为Storyboard的初始视图控制器。如果视图控制器需要根据条件更改,或者应用程序没有主界面,则可以通过编程方式初始化UIWindow并设置其根视图控制器。 - JAL
2
这里令人惊讶(但是好的)一件事情是,以这种方式手动实例化视图控制器似乎阻止了iOS实例化默认的视图控制器。我本来可能会期望两者都被加载。这种行为有没有在某个地方有记录? - Pat Niemeyer
2
@MayankJain 这在 Swift 3 中可以正常工作,只需要将一些早期 Swift 的代码翻译一下即可。 - JAB
显示剩余4条评论

50

对于新的 Xcode 11.xxx 和 Swift 5.xx,目标设置为 iOS 13+。

在新项目结构中,AppDelegate 不需要处理 rootViewController 相关内容。

有一个新类用于处理 window(UIWindowScene) 类 -> 'SceneDelegate' 文件。

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?

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

    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = // Your RootViewController in here
        self.window = window
        window.makeKeyAndVisible()
    }

}

2
非常感谢。 - Azim Talukdar
我曾尝试在AppDelegate中以旧的方式实现这个功能,但它无法正常工作。这让我感到困惑。这篇文章帮了我很多,谢谢! - F. Morales

44

试试这个。例如: 您应该将UINavigationController用作初始视图控制器。然后,您可以从故事板设置任何视图控制器为根视图控制器。

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let navigationController = storyboard.instantiateInitialViewController() as UINavigationController
    let rootViewController = storyboard.instantiateViewControllerWithIdentifier("VC") as UIViewController
    navigationController.viewControllers = [rootViewController]
    self.window?.rootViewController = navigationController
    return true
}

请查看我的故事板画面。


你在Storyboard中为你的视图控制器设置了Storyboard ID吗?请参考http://joxi.ru/l2ZYxZqS8JOomJ - protikhonoff
是的,已经设置好了,我认为它成功地打开了视图控制器,但它没有“显示”出来。有什么想法吗? - Abubakar Moallim
没有错误,在屏幕启动后,我得到了一个黑色的页面。 - Abubakar Moallim
我猜我找到了问题所在。你应该在你的故事板中检查“是否为初始视图控制器”。http://joxi.ru/8AnNbQlhq3QOAO - protikhonoff
但我想使用条件语句更改初始视图控制器。 - Abubakar Moallim
我也遇到了这个问题,即使你在应用程序委托中重定向了初始视图控制器,在故事板中仍然要检查一个初始视图控制器。 - Andrew Cook

32

Swift 3,Swift 4:

将第一行更改为

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

其余部分相同。

Swift 5+:

从故事板实例化根视图控制器:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // this line is important
        self.window = UIWindow(frame: UIScreen.main.bounds)

        // In project directory storyboard looks like Main.storyboard,
        // you should use only part before ".storyboard" as its name,
        // so in this example name is "Main".
        let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
        
        // controller identifier sets up in storyboard utilities
        // panel (on the right), it is called 'Storyboard ID'
        let viewController = storyboard.instantiateViewController(withIdentifier: "YourViewControllerIdentifier") as! YourViewController

        self.window?.rootViewController = viewController
        self.window?.makeKeyAndVisible()        
        return true
    }

如果你想将UINavigationController用作根视图控制器:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // this line is important
        self.window = UIWindow(frame: UIScreen.main.bounds)

        let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
        let viewController = storyboard.instantiateViewController(withIdentifier: "YourViewControllerIdentifier") as! YourViewController
        let navigationController = UINavigationController.init(rootViewController: viewController)
        self.window?.rootViewController = navigationController

        self.window?.makeKeyAndVisible()        
        return true
    }

从xib实例化根视图控制器:

这几乎是相同的,但是不要使用这些行:

let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "YourViewControllerIdentifier") as! YourViewController

你得写。

let viewController = YourViewController(nibName: "YourViewController", bundle: nil)

22

如果您没有在使用故事板,您可以尝试这个方法。

var window: UIWindow?
var initialViewController :UIViewController?

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    initialViewController  = MainViewController(nibName:"MainViewController",bundle:nil)

    let frame = UIScreen.mainScreen().bounds
    window = UIWindow(frame: frame)

    window!.rootViewController = initialViewController
    window!.makeKeyAndVisible()

    return true
}

1
nib名称是指什么? - Abubakar Moallim
@Abs nibName 是要加载以实例化视图的 Nib 的名称。 - rashii
这会导致方向转换动画停止工作。 - user3427013
我已经点赞了,哈哈... "必须初始化窗口然后设置它的框架,必须初始化窗口然后设置它的框架,必须初始化窗口然后设置它的框架" - 我自言自语 - Chris Allinson

18

Swift 4.2和5版本的代码:

var window: UIWindow?


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 
     self.window = UIWindow(frame: UIScreen.main.bounds)

     let storyboard = UIStoryboard(name: "Main", bundle: nil)

     let initialViewController = storyboard.instantiateViewController(withIdentifier: "dashboardVC")

     self.window?.rootViewController = initialViewController
     self.window?.makeKeyAndVisible()
}

对于 Xcode 11+ 和 Swift 5+:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

     var window: UIWindow?

     func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
         if let windowScene = scene as? UIWindowScene {
             let window = UIWindow(windowScene: windowScene)

              window.rootViewController = // Your RootViewController in here

              self.window = window
              window.makeKeyAndVisible()
         }
    }
}

self.window报错:类型“AppDelegate”没有成员“window”,有什么想法吗? - Joseph Astrahan
@JosephAstrahan 在使用变量之前要先声明它。例如 - var window: UIWindow? - Jamil Hasnine Tamim
@JosephAstrahan请再次检查我的答案。我添加了变量。 - Jamil Hasnine Tamim
谢谢,这非常有帮助! - Joseph Astrahan
我把LaunchViewController放在解决方案中说“在这里放置您的RootViewController”的位置,但是出现了以下错误:无法将类型为'LaunchViewController.Type'的值分配给类型为'UIViewController'的变量。----- 我做错了什么? - user3140521
显示剩余4条评论

14

以下是一个不错的方法。该示例将导航控制器作为根视图控制器,并将您选择的视图控制器放置在导航堆栈底部,准备好让您从中推送所需内容。

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
    // mainStoryboard
    let mainStoryboard = UIStoryboard(name: "MainStoryboard", bundle: nil)

    // rootViewController
    let rootViewController = mainStoryboard.instantiateViewControllerWithIdentifier("MainViewController") as? UIViewController

    // navigationController
    let navigationController = UINavigationController(rootViewController: rootViewController!)

    navigationController.navigationBarHidden = true // or not, your choice.

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

    self.window!.rootViewController = navigationController

    self.window!.makeKeyAndVisible()
}
为了让这个示例运行起来,您需要将“MainViewController”设置为主视图控制器上的Storyboard ID,并且在这种情况下,storyboard的文件名应为“MainStoryboard.storyboard”。我会以这种方式重命名我的storyboard,因为对我来说,“Main.storyboard”不是一个适当的名称,特别是如果您曾经去子类化它。

11

我已经用Objective-C完成了它。希望对你有用。

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];

UIViewController *viewController;

NSUserDefaults *loginUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *check=[loginUserDefaults objectForKey:@"Checklog"];

if ([check isEqualToString:@"login"]) {
    
    viewController = [storyboard instantiateViewControllerWithIdentifier:@"SWRevealViewController"];
} else {
    
    viewController = [storyboard instantiateViewControllerWithIdentifier:@"LoginViewController"];
}


self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];

你是如何在Storyboard中设计View Controllers的?请帮忙。 - TechSavy
拖动视图控制器并设置标识符的故事板ID:<ViewControllerName>,然后访问您的视图控制器... - Patel Jigar
@PatelJigar 如何在loginvc中进行设置 - Uma Madhavi
像这样调用视图控制器UITabBarController *tbc = [self.storyboard instantiateViewControllerWithIdentifier:@"ContentViewController"];[self presentViewController:tbc animated:YES completion:nil]; - Patel Jigar

8
在AppDelegate中初始化ViewController [初始化视图控制器] 禁用Main.storyboard
1. (old Xcode)General -> Deployment Info -> Main Interface -> remove `Main` 
2. Info.plist -> remove Key/Value for `UISceneStoryboardFile` and `UIMainStoryboardFile`

添加故事板ID

Main.storyboard -> Select View Controller -> Inspectors -> Identity inspector -> Storyboard ID -> e.g. customVCStoryboardId

[使用故事板设置初始视图控制器(而不是Main)]
Swift 5和Xcode 11

扩展UIWindow

class CustomWindow : UIWindow {
    //...
}

由Xcode生成的编辑SceneDelegate.swift

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: CustomWindow!

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        
        guard let windowScene = (scene as? UIWindowScene) else { return }

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let initialViewController = storyboard.instantiateViewController(withIdentifier: "customVCStoryboardId")

        //or if your storyboard has `Is Initial View Controller`
        let storyboard = UIStoryboard(name: String(describing: SomeViewController.self), bundle: nil)
        let initialViewController = storyboard.instantiateInitialViewController()

        window = CustomWindow(windowScene: windowScene)
        window.rootViewController = initialViewController
        window.makeKeyAndVisible()
    }

    //...
}

访问框架包
从框架获取故事板


可以将根控制器设置为初始视图控制器window.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() - Kamran Khan

7

如果您没有使用storyboard,可以通过编程方式初始化主视图控制器。

Swift 4

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

    let rootViewController = MainViewController()
    let navigationController = UINavigationController(rootViewController: rootViewController)
    self.window = UIWindow(frame: UIScreen.main.bounds)
    self.window?.rootViewController = navigationController
    self.window?.makeKeyAndVisible()

    return true
}

class MainViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .green
    }
}

同时从部署信息中移除Main

enter image description here


这在Swift 4.2,XCode 11.3,IOS 9 ~ 13.3.1中对我有效。 - Coder ACJHP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接