iOS 7.1 removeFromSuperview崩溃
我的应用程序没有任何崩溃,直到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];}
- (void) dealloc { [mainView removeFromSuperview]; [mainView release] [super dealloc];}
在mainView removeFromSuperview我的应用程序崩溃。
你的程序崩溃了,因为你不止一次地释放了一些东西。 这部分是显而易见的。
find它的第一步是在debugging器中启用僵尸检测。 ( Project->Schemes->Edit Scheme->Diagnostics->Enable Zombie Objects
)。 这里的目标是让你的程序更快崩溃。 当你尝试访问一个解除分配的实例时,这将使你进入debugging器。 有时候,这会让你指向正确的方向,有时候却不是,但是最好将它尽可能地放在问题的尽头附近。
下一步是使用僵尸工具。 这个工具会给你比上一步更多的信息,但是使用起来比较复杂(这就是为什么我要做第2步而不是第1步)。 僵尸工具将跟踪所有的分配和释放,并检测您何时尝试访问僵尸对象。
最后的手段是开始评论代码。 首先注释掉你的程序在创build视图控制器(崩溃的那个)和释放它之间的所有事情。 然后运行该程序,并执行所需的任何操作,使其显示错误的视图控制器。 它显然不会做任何事情,因为它现在只是一个空的视图控制器,但它不应该崩溃)。 然后开始取消注释代码块,一次一点,并在每次迭代之间继续运行它。 这是一个重复的过程,如果您的视图控制器代码很大且很复杂,那么这个过程可能会很乏味。 但是我们的想法是不断地将代码添加回来,直到你添加了一些东西然后崩溃 – 那么你就知道你find了导致问题的代码片断。 你必须在这里有创意,并仔细select你如何把你的代码放回 – 如果你的程序有一个很好的模块化devise,你应该能够做到这一点,没有太多的麻烦。 意大利面条代码将很难做到这一点,但它可能会给你一个很好的机会来重组你的代码。 通过这个过程,你将会缩小问题的范围,最终通过消除的过程findbug。
在快速枚举数组的时候修改数组通常不是个好主意。 您似乎在视图的子视图数组上使用快速枚举,并且同时修改该数组(通过随时删除子视图)。 你可以尝试这样的事情:
NSArray *subviewsCopy = [[contentVc subviews] copy]; for (UIView *subview in subviewsCopy) { [subview removeFromSuperview]; }
但是,正如其他一些人所说,有一点奇怪,你需要去手动删除这些子视图的麻烦。 在正常情况下,当视图控制器本身被释放时,视图控制器的视图(及其下的视图层次)将被自动清除。
还有一些好的工具可以帮助你追踪问题的根源。 尤其是,您应该在您的应用程序(在Xcode,产品菜单下)中进行configuration文件,并在仪器提示时select“僵尸”工具。 使用僵尸,您可以看到在释放对象之后被保留/释放的对象的保留/释放历史logging。
如果您试图手动清除视图层次结构,因为您怀疑您的视图将被泄露,我build议您也尝试在乐器中的泄漏工具,并validation当禁用此代码相关的视图实际上泄漏。
更新
尝试这样做:
NSArray *subviews = [NSArray arrayWithArray:[contentVc subviews]]; for (UIView *subView in subviews) [subView removeFromSuperview];
我认为你崩溃是因为你想快速枚举一个具有可变长度的数组(事实上,当你删除一个子视图,它也从子视图数组中删除)。
如果你想删除viewcontroller,只需调用:
[contentVc.view removeFromSuperView]; [contentVc removeFromParentViewController];
有时会因为:
[myactualviewcontroller.view removeFromSuperview];
您不应该从视图层次手动添加或移除控制器的视图,而是依赖于UIWindow
的rootViewController
,将您的控制器推送到UINavigationController
等,以使系统将视图添加到私有底层超级视图。 除非你创build一个自定义容器视图控制器 ,我猜你不是。
如果你只是想手动处理视图不使用视图控制器,因为他们不会被系统保留,他们将不会得到任何旋转消息,等等。因此,无论如何使用视图控制器是毫无意义的。
至于子视图的内存处理,子视图是由他们的超级视图保留的,所以只要你不保留strong
引用,你就不需要发布子视图,只需删除一个共同的超级视图即可。
再次,如果你正确使用视图控制器只是释放控制器将摆脱所有的意见。
最后,你应该开始使用ARC。
1.根据苹果的文档 ,调用removeFromSuperview将从超级视图中删除该视图,并自动释放它。
所以,如果你使用的是removeFromSuperview,那么你不应该调用[removedView release],这会使应用程序崩溃。
请参阅Apple的截图。
在你的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];
相反,你可以通过苹果的这一行来实现相同的效果。
[[contentVc subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
请确保在删除视图前删除所有可能的委托(即someScrollViewDelegate = nil;
之前[someScrollView removeFromSuperview];
)一个/或animation完全完成(所有CATransaction
, [UIViev beginAnimation...]
, [UIView animateWithDuration...]
等)。
请执行以下操作:
1- for (UIView *subView in [contentVc subviews])
debuggingfor (UIView *subView in [contentVc subviews])
并检查迭代次数。
如果在第一次打击时不会崩溃,则可以在删除视图之前添加此行if (subView.superView != nil)
否则,请确保不会在其他地方发布视图,因为它会一直显示,不会崩溃,直到从超级视图中移除。
UPDATE2:我会认为你会意识到内存泄漏,并且你有很好的经验。
-
每当你将一个子视图添加到一个视图中时,除了原始的1之外,这个对象将会保留1,等于2,然后在添加子视图之后直接释放它,这会将保留计数递减到1。 这里有个小诀窍:你不必释放子视图或者从父视图中删除子视图来摆脱剩余的保留计数。 你可以简单地删除或释放父视图。 得到NSMutableArray作为一个例子。
-
删除
[mainView removeFromSuperview];
从dealloc:
方法。 你可以添加它,如viewWillDisappear:
方法。 除了释放调用之外,dealloc方法不应该包含其他任何东西。
代替:
for (UIView *subView in subviews) [subView removeFromSuperview];
尝试:
[subviews makeObjectsPerformSelector:@selector(@"removeFromSuperview");