iOS 7.1 removeFromSuperview崩溃

问题描述 投票:13回答:9

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

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

我得到

-[CALayer保留]:发送到已释放实例的消息

消息

[actual removeFromParentViewController];

是删除它的好方法吗?并会释放整个视图控制器及其子视图吗?因为我的应用没有崩溃,而不是removeFromSuperview。我不了解iOS 7.1中的更改​​。

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

更新:

有时会崩溃:

[myactualviewcontroller.view removeFromSuperview];

-[CALayer保留]:发送到已释放实例的消息

为什么?

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

[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上,我的应用程序崩溃了。

ios objective-c subview ios7.1
9个回答
6
投票

您的程序崩溃,因为您不止一次发布了一些东西。这部分是显而易见的。

找到它的第一步是在调试器中启用僵尸检测。 (Project->Schemes->Edit Scheme->Diagnostics->Enable Zombie Objects)。目的是使程序尽早崩溃。一旦您尝试访问已释放实例,这将使您进入调试器。有时,这会为您指明正确的方向,有时甚至会指向正确的方向,但是最好始终将其检测到尽可能靠近问题所在的位置。

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

最后的选择是开始注释代码。首先注释掉程序在创建视图控制器(崩溃的那个)到释放它之间的所有操作。然后运行该程序,并执行所需的任何操作以使其显示不良视图控制器。显然,它不会做任何事情,因为它现在只是一个空的视图控制器,但不应崩溃)。然后,一次取消一点代码块的注释,并在每次迭代之间继续运行它。这是一个重复的过程,如果您的视图控制器代码又大又复杂,可能会很乏味。但是我们的想法是不断添加代码,直到您添加了一些东西,然后它崩溃了,然后您才知道您已经找到了导致问题的代码。您必须在这里发挥创造力,并仔细选择如何放回代码-如果您的程序具有良好的模块化设计,那么您应该能够做到这一点而没有太大的麻烦。 Spaghetti代码很难做到这一点,但是它可能会给您一个很好的机会,让您在编写代码时对其进行重组。通过执行此过程,您可以缩小问题范围,并最终通过消除过程来发现错误。


7
投票

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

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

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

也有一些很好的工具可以帮助您追踪问题的根源。特别是,您应该分析您的应用程序(在Xcode中的“产品”菜单下),并在Instruments提示您时选择“僵尸”工具。使用“僵尸”,您可以查看在释放对象后收到消息的对象的保留/释放历史记录。

如果您尝试手动清理视图层次结构,因为您怀疑视图会被泄漏,建议您也尝试使用Instruments中的Leaks工具,并验证当禁用此代码时,相关视图是否确实泄漏了。


2
投票

更新

尝试这样做:

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

我认为您崩溃是因为您试图快速枚举具有可变长度的数组(实际上,当您删除子视图时,它也会从子视图数组中删除)。

如果要删除视图控制器,只需致电:

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

2
投票

有时会崩溃:

[myactualviewcontroller.view removeFromSuperview];

您不应该手动从视图层次结构中添加或删除控制器的视图,而要依靠UIWindowrootViewController,将控制器推到UINavigationController等,以使系统添加查看私有基础超级视图。除非您创建一个Custom Container View Controller,否则我猜不是。

如果您只想手动处理视图,请不要使用视图控制器,因为它们不会被系统保留,也不会收到任何旋转消息,等等。因此,在任何情况下,使用视图控制器都是没有意义的。

关于子视图的内存处理,子视图由其父视图保留,因此,只要您不保留strong引用,就无需释放子视图,只需删除一个公共的父视图。

同样,如果您正确使用视图控制器,则只需释放该控制器将摆脱所有视图。

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


1
投票

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

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

请从Apple参考此屏幕截图。

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9pMkRjYS5wbmcifQ==” alt =“在此处输入图像描述”>

在您的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)];

1
投票

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


1
投票

请执行以下操作:


0
投票

而不是:


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.