20

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这只是 Xcode 在幕后初始化吗?

4

5 回答 5

31

我的书中

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

于 2013-05-08T17:42:38.420 回答
4

UIWindow文档中:

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

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

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

使用情节提要,在加载主情节提要时在幕后创建窗口(有关更多信息,请参阅View Controller Programming Guide)。

于 2013-05-08T16:43:07.657 回答
2

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

主情节提要初始化您的应用程序的用户界面

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

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

于 2013-05-08T16:42:42.887 回答
2

上面只回答了谁设置了 window 变量而没有回答主要问题:“但是如果 window 从未显式初始化,它如何具有非 nil rootViewController?这只是 Xcode 在幕后初始化吗?” 并且似乎暗示着魔法正在发生。对我来说不是一个令人满意的答案,所以稍微挖掘一下,一切都变得清晰起来。

生成的代码将 AppDelegate 定义为

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

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

    optional public var window: UIWindow? { get set }

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

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

optional public func applicationDidEnterBackground(_ application: UIApplication)

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

为了完整起见,请注意类上的@UIApplicationMain标记。这定义了应用程序的入口点,并且是使一切协同工作的原因。实际的类名是无关紧要的,只要它是 UIResponder 类型并且符合 UIApplicationDelegate 即可。

于 2017-12-06T02:56:17.390 回答
1

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

箭

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

界面

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

于 2013-05-08T16:36:33.190 回答