在AppDelegate中,主UIWindow如何实例化?

Master-Detail Xcode项目中的默认代码片段


AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController; // *** here *** MasterViewController *controller = (MasterViewController *)navigationController.topViewController; controller.managedObjectContext = self.managedObjectContext; return YES; } 

AppDelegate.h

 @property (strong, nonatomic) UIWindow *window; 

我知道@synthesize只是设置访问器方法,并不会自动进行初始化。 但是,如果window没有显式初始化, window如何具有非零的rootViewController呢? 这只是Xcode启动幕后?

从我的书中 :

如果您在指定模板时select了Storyboard选项,则该过程的工作方式会有所不同。 该应用程序被赋予一个主要的故事板,由Info.plist键“主要故事板文件基本名称”( UIMainStoryboardFileUIMainStoryboardFile 。 在UIApplicationMain实例化应用程序委托类后,它向应用程序委托请求其window属性的值; 如果该值为零,则创build该窗口并将其分配给应用程序委托的window属性。 故事板的初始视图控制器然后被实例化并被分配给窗口的rootViewController属性,其结果是其视图作为其根视图被放置在窗口中; 窗口然后发送makeKeyAndVisible消息。 所有这一切都是由UIApplicationMain在幕后完成的,没有任何可见的代码。 这就是为什么在故事板模板中, application:didFinishLaunchingWithOptions:实现是空的。

UIWindow文档 :

注意:当您使用storyboard和Xcode应用程序模板来创build应用程序时,会为您创build一个窗口。

如果您不使用故事板,则会明确创build窗口,尽pipe所有标准项目模板都是这样开箱的。 在应用程序委托中你会看到类似这样的一行:

 self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; 

使用故事板时,当主要故事板加载时,窗口在幕后创build(有关更多信息,请参阅“ 视图控制器编程指南” )。

从苹果的文档(在“在您的应用程序中使用视图控制器”):

主要故事板初始化您的应用程序的用户界面

主要故事板是在应用程序的信息属性列表文件中定义的。 如果在此文件中声明了主要故事板,那么当您的应用程序启动时,iOS会执行以下步骤:

它为你实例化一个窗口。 它加载主要故事板并实例化其初始视图控制器。 它将新的视图控制器分配给窗口的rootViewController属性,然后使窗口在屏幕上可见。

在Storyboard中,有一个可以拖动的小箭头:

箭头

如果您使用的是xibs / nibs,则可以填写“主界面”字段。

接口

最后,是的,这是iOS / Xcode的魔力。

上面的答案只是设置窗口variables而不回答主要问题:“但是,如果窗口没有显式初始化,窗口如何具有非零的rootViewController?这只是Xcode在后台启动吗? 似乎暗示有魔法在进行。 对我来说不是一个满意的答案,所以稍加挖掘,一切都变得清晰起来。

生成的代码将AppDelegate定义为

 @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? ... } 

当你search这个项目的时候,没有其他的参考窗口,所以显然它应该保持为零,但实际上被设置为正确的值(通过上述方法)。 “魔术”就是AppDelegate符合UIApplicationDelegate,其中包含一个声明:

  optional public var window: UIWindow? { get set } 

符合UIApplicationDelegate的一部分是公共variables窗口的重新声明。 当基础应用程序引用协议中的variables窗口时,它实际上链接到我们class的variables窗口 。 当调用应用程序更新协议中的variables窗口时,它实际上正在更新我们的variables窗口 。 所以当我们需要访问我们的程序中的价值时,它已经准备就绪,正在等待。

不是 Xcode魔术,而是Swift语言的一个组成部分。 当使用协议时,我们可以在我们自己的Swift程序中使用相同的技术。 这和我们一直在做的类中的各种函数的实现是一样的:例如,UIApplicationDelegate定义

optional public func applicationDidEnterBackground(_ application: UIApplication)

所以我们可以编写我们自己的实现,然后“神奇地”叫!

为了完整起见 ,请注意类上的@UIApplicationMain标签。 这为应用程序定义了入口点,是什么使所有的一起工作。 实际的类名是不相关的,只要它是UIRespondertypes并且符合UIApplicationDelegate,就可以给出你需要的任何名字。