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

时间:2013-05-08 16:32:20

标签: ios objective-c xcode

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从未明确初始化,rootViewController如何具有非零{{1}}?这只是Xcode在幕后启动吗?

5 个答案:

答案 0 :(得分:24)

来自my book

  

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

答案 1 :(得分:4)

来自UIWindow documentation

  

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

如果您不使用故事板,则会显式创建窗口,但所有标准项目模板都是开箱即用的。您将在应用委托中看到与此类似的行:

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

使用故事板,在加载主故事板后,将在幕后创建窗口(有关详细信息,请参阅View Controller Programming Guide)。

答案 2 :(得分:2)

来自Apple的文档(在“在应用程序中使用视图控制器”):

  

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

     

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

     

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

答案 3 :(得分:1)

在你的故事板中,你可以拖动一个小箭头:

arrow

如果您使用的是xibs / nibs,那么主界面就是'字段将被填写。

interface

最后,是的,它是iOS / Xcode魔术。

答案 4 :(得分:1)

以上答案只有谁设置窗口变量而没有回答主要问题:“但是如果窗口永远没有显式初始化,那么窗口如何有一个非零的rootViewController?这只是Xcode在幕后初始化吗?”而且似乎暗示着有魔力在进行。对我来说不是一个令人满意的答案,所以通过一点挖掘,一切都变得清晰。

生成的代码将AppDelegate定义为

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

当你搜索项目时,没有其他对窗口的引用,所以显然它应该保持为零,但实际上设置为正确的值(通过上面概述的方法)。 “神奇”是AppDelegate符合包含声明的UIApplicationDelegate:

    optional public var window: UIWindow? { get set }

符合UIApplicationDelegate的部分是公共变量 window 的重新声明。当底层应用程序引用协议中的变量 window 时,它实际上链接到我们类中的变量 window 。当调用应用程序更新协议中的变量 window 时,它实际上正在更新我们的变量 window 。因此,当我们需要访问程序中的值时,它已准备就绪并等待。

这是 Xcode魔术,但是Swift语言不可或缺的一部分。使用协议时,我们可以在自己的Swift程序中使用相同的技术。这与我们一直在做的各种函数的实现相同:例如: UIApplicationDelegate定义

optional public func applicationDidEnterBackground(_ application: UIApplication)

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

为了完整性,请注意课程上的 @UIApplicationMain 标记。这定义了应用程序的入口点,是使所有内容协同工作的原因。实际的类名是无关紧要的,并且可以给出您需要的任何名称,只要它是UIResponder类型并且符合UIApplicationDelegate。