【问题标题】:iOS: different addSubview behavior between iOS 4.3 and 5.0iOS:iOS 4.3 和 5.0 之间的不同 addSubview 行为
【发布时间】:2011-12-11 11:07:21
【问题描述】:

之前在 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 中运行我的应用程序。

【问题讨论】:

  • 正如您所发现的,iOS 4 和 iOS 5 之间只有大约 10% 的更改被明确记录。

标签: iphone ios ipad uiviewcontroller ios5


【解决方案1】:

通过这种方法,你知道你使用哪个操作系统,如果小于 5.0 或其他,则设置条件

[[UIDevice currentDevice] systemVersion]

【讨论】:

  • 我知道这样可以帮上忙。我想更多地了解这些差异。
【解决方案2】:

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

就我而言,当我将视图控制器的视图作为子视图添加到另一个视图控制器的视图时,子视图仅在 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:],这个问题可能是可以解决的。

【讨论】:

【解决方案3】:

这是 iOS5 的行为:
viewWillAppear, viewDidAppear, ... 在 iOS5 的 addSubView: 之后自动执行。
因此对于 iOS5,无需手动执行 iOS
解决方法可能是:

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

【讨论】:

    【解决方案4】:

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

    如果您自己管理子视图控制器,则必须显式调用它们(并且以正确的顺序 - 尽管您应该有充分的理由这样做)。模态视图在关闭模态视图时没有收到这些调用仅仅是因为没有人可以调用它。将根视图控制器封装在UINavigationController 中(如果您愿意,可以隐藏导航栏),然后打开一个模态视图控制器。在其被解雇或弹出时,viewWillAppear 将被调用。

    【讨论】:

      【解决方案5】:

      在 iOS 4 中,在视图层次结构中添加或删除视图时,您必须手动调用 -viewWillAppear-viewWillDisappear 等。如果从 window 层次结构中添加或删除视图,它们会在 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];
        }
      

      感谢所有纠正我的人。

      【讨论】:

      • 谢谢,解决了 ios4 上的问题,但在 ios5 上 viewWillAppear 被调用了两次(一次来自我输入的手动调用)不知道为什么。
      • Richy.. 这很奇怪,因为此方法在 iOS4 中被忽略,仅在 iOS5 中调用。您可能需要仔细检查您的结果。
      • whalec:我不确定我是否同意你的编辑,所以最好留下你自己对原始问题的答案。
      • 只有在确保视图控制器已注册的情况下才能解决问题。仍然需要您使用新的addChildViewController: 方法,我在使用respondsToSelector: 后调用该方法
      • automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers 在 iOS 6 中已被弃用。
      【解决方案6】:

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

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

      如果不先将 ControllerB 添加为 ControllerA 的子级,则自动ForwardAppearanceAndRotationMethodsToChildViewControllers 将被忽略,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];
      }
      

      在ControllerB NSLogging 中的viewWillAppear:

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

      这将导致 iOS5 仅显示该 NSLog 消息两次。即您自动ForwardAppearanceAndRotationMethodsToChildViewControllers 已被忽略。

      为了解决这个问题,您需要将控制器 B 添加为控制器 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 版本字符串的可怕黑客,而是检查我们所追求的功能是否可用。

      希望这会有所帮助。

      【讨论】:

        【解决方案7】:

        在查看所有证据后,我认为最好的办法是不要对受此 ios 4 / ios 5 错误影响的视图使用 viewDidAppear 等。而是创建一个自定义类(如 viewDidAppearCustom)并自己调用它。这样你就可以保证苹果不会再次更改 sdk 并搞砸你。这里有一篇很棒的博客介绍了这个问题:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-12-12
          • 2014-11-01
          • 1970-01-01
          • 2018-05-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多