使用initWithNibName:bundle:或通过IBOutlet创建的UIViewController的行为方式不同

时间:2010-02-13 09:54:01

标签: iphone cocoa-touch uiviewcontroller iboutlet

我发现了一个奇怪的行为,并想解释我所犯的断言是错误的。

在新创建的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像素到高,并由状态栏覆盖)   - 视图未正确调整大小(例如,尝试切换“呼叫状态”栏)

为什么?

如果要重现问题,请在此处输入项目的zip存档:http://dl.dropbox.com/u/1899122/code/ProtoWindowBasedStrangeness.zip

3 个答案:

答案 0 :(得分:2)

在我冗长的答案之后,这听起来真的很傻,但你遇到的问题很容易修复(以编程方式)。

这一行:

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

实际应该是:

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

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

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

答案 1 :(得分:1)

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

我下载了你的项目并玩了一下它,它让我想到了更多关于可能发生的事情。我想我可以提供一个合理的答案,但不确定是否有一个简单的解决方案......

我认为正在发生的事情是Apple在IB中创建了一些稍微更专业的控制器对象。一个建议可能是真的是IB VC对象有一个你可以设置的属性,它没有我可以看到的UIViewController类的直接对应属性,所以IB的控制器对象可能有一些非IB UIViewController子类不能的附加功能利用。鉴于.xib中的对象是完全“冻干”的对象,Apple可能包含了我们在其IB版本中无法看到或使用的各种私有属性 - 这可能会对对象的初始化方式产生一些影响

例如,在MainWindow.xib中,选择IB VC对象,然后可以从Inspector Palette中设置属性,例如“从NIB调整视图”。如果您取消选中此项并重新运行应用程序,您将看到VC与场景B中的完全一样。因为您无法从File的Owner属性中检查此项(即使它是作为UIViewController ),你无法利用视图控制器正在做的任何事情来为你提供你想要的行为。

这样做的结果是当你使用TestViewController.xib在代码中初始化VC对象时,没有设置VC的IB特定属性,因此创建了一个标准的UIViewController,所以像“调整NIB视图”属性并设置导航项必须自己实现。

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

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

答案 2 :(得分:0)

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