iOS 7.1 removeFromSuperview 崩溃
Posted
技术标签:
【中文标题】iOS 7.1 removeFromSuperview 崩溃【英文标题】:iOS 7.1 removeFromSuperview crash 【发布时间】:2014-03-11 17:10:22 【问题描述】:在 iOS 7.1 发布之前,我的应用没有任何崩溃。现在在任何removeFromSuperview
方法上,崩溃。例如:我有视图控制器,当我想删除一个视图控制器时,我删除它的所有子视图,然后从堆栈中删除(堆栈:我将视图控制器存储在其中,用于加载新内容并加载以前的内容):
for (UIView *subView in [contentVc subviews])
[subView removeFromSuperview];
我得到了
-[CALayer retain]:消息发送到释放的实例
消息
[actual removeFromParentViewController];
有什么好办法去掉吗?它会释放整个视图控制器及其子视图吗?因为我的应用程序没有崩溃,而不是 removeFromSuperview。我不明白 ios 7.1 中发生了什么变化。
我如何在没有removeFromSuperview
的情况下删除viewController
中的所有子视图,并且不删除我的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 我的应用崩溃了。
【问题讨论】:
我用同样的方式发布子视图,iOS7.1更新没有破坏。也许检查subView
是否为零? (尽管这在技术上应该不是问题)
潜在的麻烦:contentVc
听起来像一个视图控制器(来自后缀),但你把它当作一个视图。这是故意的吗?那是什么?
除此之外,这段代码很好;您是否曾经对视图进行过弱或不安全的引用?
如果子视图在子视图数组中,子视图怎么可能为零。 (但关闭子视图不是零,我检查了它。)
为什么在移除视图控制器的时候感觉需要移除所有的子视图?完全没有必要。
【参考方案1】:
在快速枚举数组时修改数组通常不是一个好主意。您似乎在视图的子视图数组上使用快速枚举,并同时修改该数组(通过删除子视图)。你可以试试这样的:
NSArray *subviewsCopy = [[contentVc subviews] copy];
for (UIView *subview in subviewsCopy)
[subview removeFromSuperview];
但是,正如其他人所提到的,您需要费心手动删除这些子视图,这有点奇怪。在正常情况下,当视图控制器本身被释放时,视图控制器的视图(及其下的视图层次结构)将被自动清理。
还有一些很好的工具可以帮助您找出问题的根源。特别是,您应该分析您的应用程序(在 Xcode 中,在 Product 菜单下)并在 Instruments 提示您时选择 Zombies 工具。使用 Zombies,您可以查看对象在释放后收到的消息的保留/释放历史记录。
如果您因为怀疑视图会被泄露而尝试手动清理视图层次结构,我建议您也尝试使用 Instruments 中的 Leaks 工具,并验证当禁用此代码时相关视图实际上是泄露了。
【讨论】:
我的子视图不是零,也不是 NSZombies。但是,如果我尝试将其从 superview 中删除,它会崩溃【参考方案2】:你的程序崩溃了,因为你不止一次地发布了一些东西。这部分很明显。
找到它的第一步是在调试器中启用僵尸检测。 (Project->Schemes->Edit Scheme->Diagnostics->Enable Zombie Objects
)。这里的目标是让你的程序更快地崩溃。一旦您尝试访问已释放的实例,这将使您进入调试器。有时这会为您指明正确的方向,有时则不然,但最好在尽可能靠近问题的地方检测到它。
下一步是使用 Zombies 乐器。该工具将提供比上一步更多的信息,但使用起来更复杂(这就是我将其设为第 2 步而不是第 1 步的原因)。 Zombies 工具将跟踪您的所有分配和释放,并检测您何时尝试访问僵尸对象。
最后的手段是开始注释掉代码。首先注释掉你的程序在你创建视图控制器(崩溃的那个)和你释放它之间所做的一切。然后运行程序并做任何你需要做的事情来让它显示坏的视图控制器。显然,它不会做任何事情,因为它现在只是一个空视图控制器,但它不应该崩溃)。然后开始取消注释代码块,一次一点,并在每次迭代之间继续运行它。这是一个重复的过程,如果您的视图控制器代码大而复杂,可能会很乏味。但是这个想法是继续一点一点地添加你的代码,直到你添加一些东西并且它崩溃 - 然后你知道你已经找到了导致问题的代码片段。您必须在这里发挥创造力并仔细选择将代码放回原处的方式-如果您的程序具有良好的模块化设计,那么您应该可以轻松做到这一点。意大利面条式代码很难做到这一点,但它可能会给你一个很好的机会来重组你的代码。通过这个过程,您将缩小问题范围,并最终通过消除过程找到错误。
【讨论】:
非常感谢您的回答,但正如我在评论中所写的那样,我已经解决了他们的问题。我为它使用了相同的机制:“我实现了一个自定义容器,并解决了我的随机崩溃问题,启用 nszombie 并使用工具。问题是某些东西被发布了两次,但可悲的是,Xcode 没有告诉我在哪里和什么。并且崩溃不是直接在第二个版本运行之后。它在完全随机几秒钟后崩溃。现在它工作正常。谢谢你的回答“ 我投票赞成你的答案,唯一的一件事是为什么我没有删除我的问题:它可能对某人有用:)【参考方案3】:更新
尝试这样做:
NSArray *subviews = [NSArray arrayWithArray:[contentVc subviews]];
for (UIView *subView in subviews)
[subView removeFromSuperview];
我认为您遇到了崩溃,因为您试图快速枚举具有可变长度的数组(实际上,当您删除子视图时,它也会从子视图数组中删除)。
如果你想删除视图控制器,只需调用:
[contentVc.view removeFromSuperView];
[contentVc removeFromParentViewController];
【讨论】:
你的意思是NSArray *subviews = [[contentVc subviews] copy];
?否则没有区别【参考方案4】:
有时会崩溃:
[myactualviewcontroller.view removeFromSuperview];
您不应手动从视图层次结构中添加或删除控制器的视图,而应依赖UIWindow
的rootViewController
,将控制器推送到UINavigationController
等,以使系统添加私有底层superviews的视图。除非你创建了一个Custom Container View Controller,我猜你不是。
如果您只想手动处理视图,请不要使用视图控制器,因为它们不会被系统保留,也不会收到任何旋转消息等。所以在这种情况下使用视图控制器无论如何都是没有意义的.
至于子视图内存处理,子视图由它们的父视图保留,所以只要不保留strong
引用,就不需要释放子视图,移除一个普通的父视图即可。
同样,如果您正确使用视图控制器,只需释放控制器即可摆脱所有视图。
最后,您应该开始使用 ARC。
【讨论】:
我实现了一个自定义容器,并通过启用 nszombie 和使用工具解决了我的随机崩溃问题。问题是一些东西被发布了两次,但可悲的是,Xcode 没有告诉我在哪里和什么。并且崩溃不是直接在第二个版本运行之后发生的。它在几秒钟后完全随机崩溃。现在它工作正常。谢谢你的回答 而且我认为我不应该使用 ARC,ARC 的作用与您保留、释放相同,它只是计数而不是您。但我确切地知道我不需要对象的具体点,我可以释放。我可以编写有效的代码。 ARC决定对象引用计数是否为0,并释放。我也是这样做的,但是一个对象会一直存在,直到它有一个强引用(retain)或者直到大括号结束,但是我知道在几行代码之后我不需要这个对象。 ARC 的功能不仅仅是为您释放对象,它还支持自动取消weak
引用,从而避免 unsafe_unretained
引用。在大多数情况下,它也会比你更有效率,对于其余的,如果需要,你可以使用@autoreleasepool
。【参考方案5】:
1.根据Apple's documentation,调用removeFromSuperview会将该视图从superview中移除并自动释放。
所以如果你使用removeFromSuperview,那么你不应该调用[removedView release],这会导致你的App崩溃。
请参阅 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];
相反,您可以通过 Apple 的这一行来实现相同的效果。
[[contentVc subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
【讨论】:
我必须在 removeFromSuperview 之后重新设置 mainView,因为它是 viewController 的保留属性。问题不是这个。我已经解决了我的问题,我会尽快回答我的问题 这是错误的,因为 mainView 在添加到超级视图时会保留。【参考方案6】:请确保在删除视图之前删除所有可能的代理(即[someScrollView removeFromSuperview];
之前的someScrollViewDelegate = nil;
)和/或动画已完全完成(所有CATransaction
、[UIViev beginAnimation...]
、[UIView animateWithDuration...]
等)。
【讨论】:
【参考方案7】:请执行以下操作:
1- 调试for (UIView *subView in [contentVc subviews])
并检查它的迭代次数。
如果它在第一次点击时没有崩溃,您可以在删除视图之前添加此行
if (subView.superView != nil)
请尝试确保您不会在其他地方两次发布视图,因为它是 继续显示并且不会崩溃,直到您将其从超级视图中删除。
更新2: 我会认为你会意识到内存泄漏,并且你在这方面有很好的经验。
1234563保留计数回到一。这是诀窍:您不必释放子视图或将其从其父视图中删除以消除剩余的保留计数。您可以简单地删除或释放父视图。以 NSMutableArray 为例。从dealloc:
方法中删除[mainView removeFromSuperview];
。您可以将其添加到其他位置,例如 viewWillDisappear:
方法。 dealloc 方法不应包含除释放调用之外的任何内容。
【讨论】:
最酷的是这些子视图不是零,但如果我尝试删除它会崩溃 不是子视图中的nil值,是超级视图,请尝试发消息 UIView* view = [[UIView alloc]initWithFrame: self.view.frame]; [self.view addSubview: view]; [查看发布]; for (UIView* subview in self.view.subviews) [subview removeFromSuperview]; [子视图 removeFromSuperview]; [子视图 removeFromSuperview]; ' 它没有崩溃【参考方案8】:代替:
for (UIView *subView in subviews)
[subView removeFromSuperview];
试试:
[subviews makeObjectsPerformSelector:@selector(@"removeFromSuperview");
【讨论】:
【参考方案9】:尝试在 removeFromSuperview 之前先检查视图是否为 != nil
示例:@IBOutlet weak var btnSNSApple: UIView!
if self.btnSNSApple != nil
self.btnSNSApple.removeFromSuperview()
【讨论】:
以上是关于iOS 7.1 removeFromSuperview 崩溃的主要内容,如果未能解决你的问题,请参考以下文章
在 iOS 7.1 更新中自动释放的变量崩溃,但在 iOS 7.1 之前的操作系统版本中工作正常