【问题标题】:UIViewController created with initWithNibName: bundle: or via an IBOutlet behave differently使用 initWithNibName: bundle: 或通过 IBOutlet 创建的 UIViewController 行为不同
【发布时间】:2010-02-13 09:54:00
【问题描述】:

我发现了一个奇怪的行为,并希望得到解释我所做的断言是错误的。

在新创建的 WindowBased 项目的 AppDelegate 类中,我将 UIViewController 添加到窗口。
我可以通过两种不同的方式做到这一点:
- 带有 IBOutlet。在 IB 中,我只是实例化了一个 UIViewController,将其类设置为 TestViewController 并连接它(代码的场景 A)。
- 使用代码创建 UIViewController(场景 B)。

    - (void)applicationDidFinishLaunching:(UIApplication *)application {    

#define USE_IBOUTLET YES // Comment this line to switch to scenario B

#ifdef USE_IBOUTLET
    // Scenario A

    [window addSubview:theTestViewController.view];
    [window makeKeyAndVisible];
#endif


#ifndef USE_IBOUTLET
    // Scenario B

    TestViewController *theTestViewControllerProgrammatically;

    theTestViewControllerProgrammatically = [[TestViewController alloc] initWithNibName:nil bundle:nil];

    // According to Apple: "It is a good idea to set the view's frame before adding it to a window.", so let's do it
    [theTestViewControllerProgrammatically.view setFrame:[[UIScreen mainScreen] applicationFrame]];

    [window addSubview:theTestViewControllerProgrammatically.view];

    [window makeKeyAndVisible];
#endif
}

由于我没有在 IB 中对对象进行任何自定义,因此在这两种情况下我应该具有相同的行为。

场景 A,使用 IBOutlet 按预期工作。
但是场景B存在以下问题:
- 视图位置不正确(高 20 像素,并被状态栏覆盖)。
- 视图没有正确调整大小(例如,尝试切换通话中状态栏)

为什么?

如果您想重现问题,请在此处压缩项目存档:http://dl.dropbox.com/u/1899122/code/ProtoWindowBasedStrangeness.zip

【问题讨论】:

    标签: iphone cocoa-touch uiviewcontroller iboutlet


    【解决方案1】:

    在我冗长的回答之后,这听起来真的很傻,但是您遇到的问题很容易解决(以编程方式)。

    这一行:

    [theTestViewController.view setFrame:[[UIScreen mainScreen] applicationFrame]];
    

    实际上应该是:

    [theTestViewControllerProgrammaticaly setFrame:[[UIScreen mainScreen] applicationFrame]];
    

    您正在为 IB 设置的 VC 设置框架,而不是您以编程方式创建的那个。

    无论如何 - 值得注意的是,我所有的 cmets 仍然适用!如果您不使用 IB 的控制器对象(例如,设置导航栏项),您仍然需要以编程方式执行一些操作

    保罗

    【讨论】:

    • 正确。不错的收获:) 我编辑了问题和问题中链接的 zip 存档的内容。
    【解决方案2】:

    我遇到了一个与您非常相似的问题,因为我注意到 VC 对象并非都是平等的!我遇到的问题是设置导航栏项目,当文件所有者是我以编程方式实例化的视图控制器对象时,我似乎无法做到这一点。它仅在我取消归档 IB 的控制器对象时才有效。

    我下载了您的项目并尝试了一下,这让我对可能发生的事情有了更多思考。我想我可以提供一个合理的答案,但不确定是否有简单的解决方案......

    我相信苹果已经在 IB 中创建了这些更专业的控制器对象。这可能是正确的一个建议是 IB VC 对象具有您可以设置的属性,该属性没有我可以看到的 UIViewController 类的直接对应属性,因此 IB 的控制器对象可能具有非 IB UIViewController 子类不能的一些附加功能利用。鉴于 .xib 中的对象是完整的“冻干”对象,Apple 可能包含了我们在它们的 IB 版本中无法看到或使用的各种私有属性——这可能会对对象的初始化方式产生一些影响.

    例如,在您的MainWindow.xib 中,选择 IB VC 对象,您可以从 Inspector Palette 中设置其属性,例如“Resize View From NIB”。如果您取消选中此项并重新运行您的应用程序,您将看到 VC 与场景 B 中的显示完全相同。因为您无法从 File's Owner 属性中检查此项目(即使它是 UIViewController ),您无法利用视图控制器所做的任何事情来为您提供所需的行为。

    这样做的结果是,当您在代码中使用TestViewController.xib 初始化您的 VC 对象时,没有设置 VC 的任何 IB 特定属性,因此创建了一个沼泽标准 UIViewController,因此类似“ Resize View From NIB" 属性和设置导航项必须自己实现。

    我还没有找到一种方法来利用 IB 的视图控制器在我使用 initWithNibName:bundle:nibBundle 实例化它们时所具有的功能(我猜这都是我们无法访问的私有内容),但希望这可能给了你一个起点……

    当然,我可能完全错了,有人会让我看起来像个白痴!

    保罗

    【讨论】:

    • 我想我已经解决了这个问题,如果您有兴趣,请查看我自己对 UIViewControllers 子类化的问题的答案。
    • 保罗,感谢您提出问题。在您的回答中,您以“如果您尝试以编程方式实例化一个对象而不是使用 IB 对象的插座,请准备好实现 IB 版本将为您提供的一些初始化......”结束。在这个特定的上下文中,这样的代码会是什么?
    【解决方案3】:

    可能在 B 的情况下,该视图不知道状态栏的存在。您需要相应地调整它的大小并调整其位置以考虑状态栏。这是通过更改 UIView 的框架(大小)和边界(位置)属性来完成的。

    【讨论】:

    • 但是为什么呢?在 IB 中创建对象并通过 IBOutlet 机制获取它与在代码中创建相同的对象有什么不同?在 Interface Builder 中绝对没有对对象进行自定义。
    猜你喜欢
    • 2012-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-21
    • 1970-01-01
    • 2010-11-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多