iOS 7.1 removeFromSuperview崩溃

时间:2014-03-11 17:10:22

标签: ios objective-c subview ios7.1

iOS 7.1 出来之前,我的应用没有任何崩溃。现在,在任何removeFromSuperview方法上,崩溃。例如:我有视图控制器,当我想删除一个视图控制器时,我删除它的所有子视图,然后从堆栈中删除(堆栈:我在这里存储视图控制器,用于加载新内容,并加载以前的内容):

    for (UIView *subView in [contentVc subviews])
         [subView removeFromSuperview];

我得到了

  

- [CALayer retain]:发送到解除分配的实例的消息

消息

[actual removeFromParentViewController];

是删除它的好方法吗?它会释放整个视图控制器及其子视图吗?因为而不是removeFromSuperview,我的应用程序不会崩溃。我不明白iOS 7.1中的更改​​内容。

如何在没有viewController的情况下删除removeFromSuperview中的所有子视图,而不删除我的ViewController(如果我只想添加新的子视图,并删除当前内容)?

更新:

有时崩溃:

[myactualviewcontroller.view removeFromSuperview];
  

- [CALayer retain]:发送到解除分配的实例的消息

为什么???

有时如果我尝试从视图控制器视图中删除主子视图,它也会遇到同样的崩溃:

[mainView removeFromSuperview](mainView是单个UIView,添加到vc.view中)

UPDATE2 :(详细信息)

所以,我有一个容器视图。我正在向此容器添加UIViewController.view。我将视图作为子视图添加到UIViewController.view。这个视图不是本地uiview,我的意思是,它声明为implementation{ UIView* mainView }。当我的UIViewController将被解除分配时,它的- (void) dealloc { [mainView removeFromSuperview]; [mainView release] [super dealloc];} 在mainView removeFromSuperview我的应用程序崩溃。

9 个答案:

答案 0 :(得分:7)

在您快速枚举数组时修改数组通常不是一个好主意。您似乎在视图的子视图数组中使用快速枚举,并同时修改该数组(通过删除子视图)。你可以尝试这样的事情:

NSArray *subviewsCopy = [[contentVc subviews] copy];
for (UIView *subview in subviewsCopy) {
    [subview removeFromSuperview];
}

然而,正如其他人提到的那样,你需要手动删除这些子视图的麻烦,这有点奇怪。在正常情况下,当视图控制器本身被释放时,视图控制器的视图(及其下的视图层次结构)将自动清除。

还有一些好的工具可以帮助您找出问题的根源。特别是,您应该对应用程序进行概要分析(在Xcode中,在“产品”菜单下),并在“仪器”提示时选择“僵尸”工具。使用Zombies,您可以看到在解除分配后发送消息的对象的保留/释放历史记录。

如果你正在尝试手动清理视图层次结构,因为你怀疑你的视图会被泄露,我建议你也尝试使用Instruments中的Leaks工具并验证当禁用此代码时相关视图实际上已经泄露了。

答案 1 :(得分:6)

您的程序崩溃了,因为您不止一次发布了某些内容。那部分是显而易见的。

找到它的第一步是在调试器中启用僵尸检测。 (Project->Schemes->Edit Scheme->Diagnostics->Enable Zombie Objects)。这里的目标是让您的程序更快崩溃。一旦您尝试访问已释放的实例,这将使您进入调试器。有时候这会指向正确的方向,有时候却没有,但是最好将它检测到尽可能接近问题的位置。

下一步是使用Zombies乐器。此工具将为您提供比上一步更多的信息,但使用起来更复杂(这就是为什么我将其设为步骤2而不是步骤1)。 Zombies工具将跟踪您的所有分配和发布,并检测您何时尝试访问僵尸对象。

最后的办法是开始评论代码。首先注释掉程序在创建视图控制器(崩溃的控制器)和释放视图控制器之间所做的一切。然后运行程序并执行任何操作以使其显示错误的视图控制器。显然,它不会做任何事情,因为它现在只是一个空的视图控制器,但它不应该崩溃)。然后开始取消注释代码块,一次一点,并在每次迭代之间继续运行它。这是一个重复的过程,如果您的视图控制器代码庞大且复杂,则可能会很繁琐。但我们的想法是不断添加你的代码,直到你添加一些东西然后崩溃 - 然后你就知道你已经找到导致问题的代码片段了。你必须在这里有创意,并仔细选择如何重新编写代码 - 如果你的程序有一个很好的模块化设计,你应该能够毫不费力地做到这一点。 Spaghetti代码很难做到这一点,但它可能会给你一个很好的机会来重构你的代码。通过这个过程,您将缩小问题的范围并最终通过消除过程找到错误。

答案 2 :(得分:2)

<强>已更新

尝试这样做:

NSArray *subviews = [NSArray arrayWithArray:[contentVc subviews]];
for (UIView *subView in subviews)
     [subView removeFromSuperview];

我认为你得到了崩溃,因为你正在尝试快速枚举一个长度可变的数组(实际上当你删除一个子视图时,它也会从子视图数组中删除)。

如果要删除viewcontroller,只需调用:

[contentVc.view removeFromSuperView];
[contentVc removeFromParentViewController];

答案 3 :(得分:2)

  

有时崩溃:

[myactualviewcontroller.view removeFromSuperview];

您不应手动在视图层次结构中添加或删除控制器视图,而应依赖UIWindow的{​​{1}},将控制器推送到rootViewController等,让系统将视图添加到私有底层超视图。除非你创建一个Custom Container View Controller,我猜你不是。

如果您只是想手动处理视图,请不要使用视图控制器,因为它们不会被系统保留,也不会获得任何旋转消息等。因此,在这种情况下使用视图控制器毫无意义

对于子视图内存处理,子视图由其超级视图保留,因此只要您不保留UINavigationController引用,就不需要发布子视图,只需删除一个公共超级视图。

同样,如果您正确使用视图控制器,只需释放控制器即可清除所有视图。

最后,您应该开始使用ARC。

答案 4 :(得分:1)

请执行以下操作:

1-调试for (UIView *subView in [contentVc subviews])并检查它迭代的次数。

如果在第一次点击中没有崩溃,您可以在删除视图之前添加此行     if (subView.superView != nil)

否则尝试确保您不会在其他地方发布视图两次     继续显示并且不会崩溃,直到你从它的超级视图中删除它。

UPDATE2: 我会考虑你会意识到内存泄漏,并且你有很好的经验。

  • 无论何时向视图添加子视图,除了原始1之外,这将保持对象1,等于2,然后在添加子视图后直接释放它,这将减少保留计数回到一。这是诀窍:您不必释放子视图或从其父视图中删除子视图以消除剩余的保留计数。您只需删除或释放父视图即可。获取NSMutableArray作为示例。

  • [mainView removeFromSuperview];方法中删除dealloc:。你可以像viewWillDisappear:方法一样添加它。 dealloc方法不应包含除释放调用之外的任何内容。

答案 5 :(得分:1)

1.根据Apple's documentation,调用removeFromSuperview将从superview中删除该视图并自动释放。

因此,如果您使用的是removeFromSuperview,那么您不应该调用[removedView版本],这会使您的应用程序崩溃。

请参阅Apple的此屏幕截图。

enter image description here

在你的dealloc实现中,你是这样的

- (void) dealloc {

    // Removed from Parent view and released.
    [mainView removeFromSuperview];

    // no mainView exists in memory , so it crashed the App.
    [mainView release];// Comment this line to avoid the crash

    [super dealloc];
}

2.您不应将要枚举的容器静音。

You are having like this,

for (UIView *subView in [contentVc subviews])
     [subView removeFromSuperview];

相反,您可以通过Apple的这一行来实现相同的效果。

[[contentVc subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

答案 6 :(得分:1)

请确保在删除视图之前移除所有可能的代理(即someScrollViewDelegate = nil;之前[someScrollView removeFromSuperview];)和/或动画完全完成(CATransaction[UIViev beginAnimation...]全部,[UIView animateWithDuration...]等。)。

答案 7 :(得分:0)

而不是:

for (UIView *subView in subviews)
     [subView removeFromSuperview];

尝试:

[subviews makeObjectsPerformSelector:@selector(@"removeFromSuperview");

答案 8 :(得分:0)

请先检查视图是否为!= nil,然后再执行removeFromSuperview 例如:
@IBOutlet weak var btnSNSApple: UIView! if self.btnSNSApple != nil { self.btnSNSApple.removeFromSuperview() }