14

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

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

我得到了

-[CALayer retain]:消息发送到释放的实例

信息

[actual removeFromParentViewController];

是去除它的好方法吗?它会释放整个视图控制器及其子视图吗?因为我的应用程序没有崩溃,而不是 removeFromSuperview。我不明白 iOS 7.1 中发生了什么变化。

以及如何在不删除和不删除我的情况下删除所有子视图viewControllerremoveFromSuperview如果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];} 的主视图中 removeFromSuperview 我的应用程序崩溃。

4

9 回答 9

7

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

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

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

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

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

于 2014-03-20T07:42:02.507 回答
6

Your program is crashing because you are releasing something more than once. That part is obvious.

The first step in finding it is to enable zombie detection in the debugger. (Project->Schemes->Edit Scheme->Diagnostics->Enable Zombie Objects). The goal here is to make your program crash sooner. This will drop you into the debugger as soon as you try to access a deallocated instance. Sometimes this will point you in the right direction, sometimes not, but it's always better to detect it as close to where the problem is as possible.

The next step is to use the Zombies instrument. This tool will give you more information than the previous step, but it's more complex to use (which is why I made it step 2 instead of step 1). The Zombies tool will keep track of all your allocations and releases, and detect when you try to access a zombie object.

The last resort is to start commenting out code. First comment out everything your program does between the time you create the view controller (the one that crashes) and when you release it. Then run the program and do whatever you need to do to make it display the bad view controller. It won't do anything, obviously, because it's just an empty view controller now, but it should not crash). Then start uncommenting blocks of code, a little bit at a time, and keep running it in between each iteration. This is a repetitive process, and can be tedious if your view controller code is large and complex. But the idea is to keep adding your code back in little by little until you add something back and it crashes - then you know you've found the piece of code that's causing the problem. You have to be creative here and choose carefully how you put your code back in - if your program has a nice modular design, you should be able to do this without much trouble. Spaghetti code will be difficult to do this with, but it might give you a good opportunity to restructure your code while you're at it. By going through this process, you'll narrow down the problem and eventually find the bug by process of elimination.

于 2014-03-24T14:59:52.577 回答
2

更新

尝试这样做:

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

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

如果要删除视图控制器,只需调用:

[contentVc.view removeFromSuperView];
[contentVc removeFromParentViewController];
于 2014-03-11T17:30:30.883 回答
2

有时会崩溃:

[myactualviewcontroller.view removeFromSuperview];

您不应手动从视图层次结构中添加或删除控制器的视图,而应依赖UIWindow's rootViewController,将控制器推送到UINavigationController等,以使系统将视图添加到私有底层超级视图。除非你创建一个自定义容器视图控制器,我猜你不是。

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

至于子视图内存处理,子视图是由它们的父视图保留的,所以只要不保留strong引用,就不需要释放子视图,移除一个普通的父视图即可。

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

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

于 2014-03-24T02:25:28.340 回答
1

1.根据Apple的文档,调用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)];
于 2014-03-26T08:33:50.477 回答
1

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

于 2014-03-26T15:39:36.340 回答
1

请执行以下操作:

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

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

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

UPDATE2:我认为您会意识到内存泄漏,并且您在这方面有很好的经验。

  • 每当您将子视图添加到视图时,除了原始 1 之外,这将保留对象 1,这将等于 2,然后在添加子视图后直接释放它,这会将保留计数减回 1。这是诀窍:您不必释放子视图或将其从其父视图中删除以消除剩余的保留计数。您可以简单地删除或释放父视图。以 NSMutableArray 为例。

  • [mainView removeFromSuperview];dealloc:方法中删除。viewWillDisappear:您可以在其他类似方法的地方添加它。dealloc 方法不应包含除释放调用之外的任何内容。

于 2014-03-20T09:48:13.693 回答
0

Instead of:

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

Try:

[subviews makeObjectsPerformSelector:@selector(@"removeFromSuperview");
于 2015-03-16T18:13:21.260 回答
0

尝试在 removeFromSuperview 示例之前先检查视图是否为 != nil:
@IBOutlet weak var btnSNSApple: UIView! if self.btnSNSApple != nil { self.btnSNSApple.removeFromSuperview() }

于 2020-03-04T08:51:56.217 回答