iOS:iOS 4.3和5.0之间的不同addSubview行为

时间:2011-10-20 03:32:00

标签: iphone ios ipad uiviewcontroller ios5

在iOS 4.3编码之前,我发现在将视图控制器的视图添加到[superview addSubView:controller.view]的另一个视图时,控制器实例将不会收到-viewWillAppear/viewDidAppear消息,而不是在某些线程中发现相同的问题在堆栈溢出。之后,我根据需要手动调用-viewWillAppear/-viewDidAppear

但是,升级到iOS 5.0后,发生了一些活泼的UIView行为。最后我发现在iOS 5中,[superview addSubView:controller.view]会自动向控制器实例发送-viewWillAppear/-viewDidAppear消息,加上我的手动调用,每次控制器执行其行为时,都会有两条重复消息。

我也发现了类似的问题:iOS 5 : -viewWillAppear is not called after dismissing the modal in iPad

现在,问题是,在搜索苹果的文档之后,我没有找到关于这些问题的任何明确的文档。我甚至怀疑这是否是iOS 5.0中保证的视图生命周期行为。

是否有人修复类似问题或找到有关这些差异的指导方针。因为我想在4.x & 5.x iOS中运行我的应用程序。

7 个答案:

答案 0 :(得分:28)

在iOS 4中,在视图层次结构中添加或删除视图时,您必须手动调用-viewWillAppear-viewWillDisappear等。如果在窗口层次结构中添加或删除视图,则会在iOS 5中自动调用这些视图。幸运的是,iOS 5在UIViewController中有一个方法可以覆盖以将行为恢复为与iOS 4一起使用的方式。只需将其添加到UIViewController

-(BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers {
   return NO;
}

这可能是最简单的解决方案,只要您同时支持iOS 4和iOS 5.一旦您放弃对iOS 4的支持,您可以考虑修改代码以在交换视图时使用更新的方法。

编辑2012年2月5日

显然,此功能需要使用addChildViewController:方法将子视图控制器添加到主视图控制器中。 iOS4中不存在此方法,因此您需要执行以下操作:

  if ([self respondsToSelector:@selector(addChildViewController:)] ) {
     [self addChildViewController:childViewController];
  }

感谢所有纠正我的人。

答案 1 :(得分:9)

这可能不是你想要的答案,但我遇到了同样的问题。

在我的情况下,当我将视图控制器的视图添加到另一个视图控制器的视图作为子视图时,子视图仅在iOS 5.0而不是iOS 4.X中接收到viewWillAppear。

所以我添加了一个讨厌的条件。

[self.view addSubview:self.viewController.view];
if ([[[UIDevice currentDevice] systemVersion] compare:@"5.0"] == NSOrderedAscending) {
    [self.viewController viewWillAppear:animated];
}

从iOS 5.0开始,Apple provides a way to implement custom container view controllers like UINavigationController or UITabController。我认为这种变化会影响调用viewWillAppear的时间。

如果我们使用-[UIViewController addChildViewController:],则可以解决此问题。

答案 2 :(得分:5)

上面的答案略显不完整。 我们假设您有2个视图控制器,ControllerA和ControllerB。

ControllerA.view已添加到窗口(它是父窗口),并且您想要将ControllerB.view添加为ControllerA的子视图。

如果您不首先将ControllerB添加为ControllerA的子级,则将忽略automaticForwardAppearanceAndRotationMethodsToChildViewControllers,iOS5仍将调用您,这意味着您将两次调用视图控制器回调。

ControllerA中的示例:

- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers {
    return NO;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.controllerB = [[ControllerB alloc] initWithNibName:@"ControllerB" bundle:nil];

    [self.view addSubview:self.controllerB.view];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.controllerB viewWillAppear:animated];
}

在viewWillAppear中的ControllerB NSLogging中:

- (void)viewWillAppear:(BOOL)animated
{
    NSLog("@ControllerB will appear");
}

这将导致iOS5仅显示两次NSLog消息。即你被自动转发的外观和转动方法已被忽略。

为了解决这个问题,您需要将controllerB添加为控制器a的子节点。

回到ControllerA的课程:

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.controllerB = [[ControllerB alloc] initWithNibName:@"ControllerB" bundle:nil];
    if ([self respondsToSelector:@selector(addChildViewController:)])
        [self addChildViewController:self.controllerB];

    [self.view addSubview:self.controllerB.view];
}

这将在iOS4和iOS5中按预期工作,而不是通过检查iOS版本字符串的可怕黑客,而是检查我们所追求的功能是否可用。

希望这有帮助。

答案 3 :(得分:2)

这是iOS5行为:
viewWillAppear,viewDidAppear,...在addSubView:for iOS5之后自动执行。
因此,对于iOS5,无需手动执行这些方法,因为iOS< 5.0需要。

修复可能是:

if ([[UIDevice currentDevice].systemVersion doubleValue] < 5.0) {
...execute viewWillAppear or other
}

答案 4 :(得分:0)

通过这种方法你知道哪个使用和放置条件,如果小于5.0或其他

[[UIDevice currentDevice] systemVersion]

答案 5 :(得分:0)

view{Will,Did}Appearview{Will,Did}Disappear视图控制器上的功能,而不是视图。这些功能由SDK提供的视图控制器调用,这些控制器应该管理其他视图控制器,例如UITabBarControllerUINavigationBarController

如果您自己管理子视图控制器,则必须明确调用它们(并按正确顺序 - 尽管您应该有充分的理由这样做)。在解雇模态视图时没有获得这些调用的模态视图仅仅是因为没有人可以调用它。将根视图控制器封装在UINavigationController中(如果愿意,隐藏导航栏),然后打开模态视图控制器。在被解雇或流行时,viewWillAppear将被召唤。

答案 6 :(得分:0)

在审核完所有证据后,我认为最好的办法是不要使用viewDidAppear等来查看受此ios 4 / ios 5错误影响的视图。而是创建一个自定义类(如viewDidAppearCustom)并自己调用它。通过这种方式,你可以保证苹果不会再次改变sdk并弄乱你。这里有一个很棒的博客报道这个问题:

http://gamesfromwithin.com/view-controller-notification-changes-on-ios5