Xcode 9中的UINavigationController方法setToolbarHidden bug:自动布局约束的无限计算导致OOM

时间:2017-09-25 15:57:08

标签: ios objective-c iphone uinavigationcontroller ios11

我有notifications嵌套在WhiteboxImpl.invokeMethod(<class object>, “<Name of the private Method>",input param1, input param2,…); 的实例。我使用导航控制器来访问一些视图控制器(标签栏仍然可见),我从中切换到第二个视图控制器(标签栏不再可见)。

在第二个视图控制器中,只要我打电话给: UINavigationController 应用程序冻结,内存增长,直到OOM异常崩溃。

我承认不推荐将导航控制器嵌套在标签栏中,但是这个设置似乎在iOS 11之前正常工作。

编辑:停止执行时,我看到很多调用:

UITabBarController

[self.navigationController setToolbarHidden:NO]

UIView(UIConstraintBasedLayout)

这里是完整的堆栈跟踪

UIView(AdditionalLayerSupport)

2 个答案:

答案 0 :(得分:3)

这是OP来自同一团队的开发人员的答案。

经过一轮研究后,我们发现问题出在我们身边:

- (NSArray *)toolbarItems
{
  return [self toolbarItemsWithRunningAdditionalAnimation:NO];
}

原始开发人员使方法toolbarItemsWithRunningAdditionalAnimation在每次调用方法时都返回新对象。当进入这个控制器时,iOS调用toolbarItems至少3次,所以每当我们让iOS混淆时给它新的对象,所以它在无限循环中重新计算自动布局约束。我们下面的原始修复工作也正常,但它已经过时,因为我们开始总是返回相同的项目数组,如:

- (NSArray *)toolbarItems {
  if (_cachedToolbarItems) { return _cachedToolbarItems; }

  _cachedToolbarItems = [self toolbarItemsWithRunningAdditionalAnimation:NO];

  return _cachedToolbarItems'
}

我们在app(伪代码)中执行以下操作:

UIToolbar *toolbar = self.navigationController.toolbar;

NSArray <UIBarButtonItem *> *items = @[
  flexibleSpace, 
  share, 
  flexibleSpace, 
  play, 
  flexibleSpace, 
  stats, 
  flexibleSpace
];
[toolbar setItems:items animated:animated];

[self.navigationController setToolbarHidden:NO animated:animated];

导致无限计算自动布局约束的有问题的项目是sharestats。它们都有共同之处 - 它们都是使用-[UIBarButtonItem initWithImage:style:target:action:]初始化程序创建的。当我们开始使用另一个初始化程序时:

 UIButton *customShareButton = ... // we create button ourselves.
 UIBarButtonItem *shareItem = [[UIBarButtonItem alloc] initWithCustomView: customShareButton];

问题消失了。

答案 1 :(得分:2)

除了接受的答案,我们发现我们的问题与我们的课程中覆盖该方法的事实有关 - (NSArray *)toolbarItems

每次调用我们的方法时,都会创建一组新的toolbarItem。 似乎从iOS 11开始,每次工具栏项都返回到此方法时,会再次调用UINavigationController:layoutIfNeeded,而toolbarItems又会调用- (NSArray *)toolbarItems,因为我们的实现会返回新项目。这会导致无限循环。

如果您遇到此问题,请检查您是否覆盖var data2 = []; for(var i in data1){ data2.push(data1[i].name) }