可以在这个例子中解释代码流吗??内存泄漏?在哪里?

Posted

技术标签:

【中文标题】可以在这个例子中解释代码流吗??内存泄漏?在哪里?【英文标题】:Possible to explain code flow in this example ?? Memory leak? Where? 【发布时间】:2011-07-06 15:57:57 【问题描述】:

参考这个 PageControl 示例,有人可以解释一下代码流程吗? Instruments 在这里给了我一个漏洞,所以寻求帮助。

回复:本教程: http://www.edumobile.org/iphone/iphone-programming-tutorials/pagecontrol-example-in-iphone/

我们在 AppDidFinishLaunching 方法中为 Null 对象初始化一个数组...

NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < kNumberOfPages; i++) 
    [controllers addObject:[NSNull null]];

self.viewControllers = controllers;
[controllers release];

然后调用:

[self loadScrollViewWithPage:0];
[self loadScrollViewWithPage:1];

这是 loadScrollViewWithPage 的实现:

- (void)loadScrollViewWithPage:(int)page 
if (page < 0) return;
if (page >= kNumberOfPages) return;

PageControlExampleViewControl *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null]) 
    controller = [[PageControlExampleViewControl alloc] initWithPageNumber:page];
    [viewControllers replaceObjectAtIndex:page withObject:controller];
    [controller release];


if (nil == controller.view.superview) 
    CGRect frame = scrollView.frame;
    frame.origin.x = frame.size.width * page;
    frame.origin.y = 0;
    controller.view.frame = frame;
    [scrollView addSubview:controller.view];


Instruments 在以下行的这个实现中给了我一个漏洞:

if (nil == controller.view.superview)

有人知道为什么这会是 Instruments 报告的泄漏吗?我的代码是相同的。 同样在初始调用 [self loadScrollViewWithPage:0]; 之后,在第一次通过并创建对象时,BOTH if 子句 被传递并输入。

这怎么可能? 如果我们输入第一个 if 子句,我们分配并创建我们的控制器并以**释放*它结束([控制器释放])。

下一行 (if (nil == controller.view.superview)) 不应该产生一个 EXC_BAD_ACCESS 错误,就像我们刚刚发布的 controller 一样吗?

仪器屏幕截图:

【问题讨论】:

【参考方案1】:

我不知道 Instruments 为什么会报告该行的泄漏,除非它只是注意到 controller.view 是由该行分配的(访问 UIViewController 的视图属性会在必要时自动加载视图)并且尚未释放(只要 scrollView 存在并且 controller.view 仍然是它的子视图,它就不应该是它)。

它通过两个if 子句是正确的。第一个if 检查该页面索引是否确实存在视图控制器,如果不存在则创建一个(但将其添加到scrollView)。第二个检查页面索引的视图控制器的视图是否已经添加到滚动视图中,如果没有,则添加它。

它没有崩溃的原因是因为[viewControllers replaceObjectAtIndex:page withObject:controller] 将控制器添加到了一个 NSMutableArray 中,该 NSMutableArray 保留了该控制器。这样做可能会稍微不那么令人困惑:

if ((NSNull *)controller == [NSNull null]) 
    controller = [[[PageControlExampleViewControl alloc] initWithPageNumber:page] autorelease];
    [viewControllers replaceObjectAtIndex:page withObject:controller];

【讨论】:

添加了受影响线路的仪器输出屏幕截图。我真的不知道为什么会泄漏,因为正如您所说。虽然 controller.viewnot 滚动视图的子视图,但它正在泄漏?它将它添加到它即将进入的那个子句中? 从您的屏幕截图中,它抱怨分配的视图。报告泄漏的行是分配视图之前程序中的最后一行。您是否在某个时候泄漏了滚动视图?这可能会导致 Instruments 将其所有子视图也视为已泄露。【参考方案2】:

在我看来,您没有正确释放 scrollView。

【讨论】:

【参考方案3】:

这怎么可能?如果我们输入第一个 if 子句,我们分配并创建我们的控制器,并以 *释放它([控制器释放])结束。

下一行(如果 (nil == controller.view.superview))不应该产生 EXC_BAD_ACCESS 错误,因为我们刚刚在上面发布了控制器?

看看 alloc 和 release 之间的界限。

[viewControllers replaceObjectAtIndex:page withObject:controller];

viewControllers 数组将保留控制器。

但恕我直言,这不是好的代码。正是你所说的原因。乍一看不是很清楚。

【讨论】:

我的理解是 viewControllers 将保留 ViewController 是的,但是自从 [controller release] 之后,它应该不再可以通过该 *controller 指针访问它吗?仅通过 [viewControllers objectAtIndex:page] ? 当一个对象被保留时,它在内存中的位置保持不变。并且控制器指针仍然引用内存中的相同地址。释放既不改变指针也不改变对象的地址。这就是我们得到所有 BAD_ACCESS 错误的原因。 那么 [controller] 释放调用是多余且不必要的,因为我们通过将对象放入数组中来保留它? 不,不是多余的。规则说如果你分配你必须释放。当您从数组中删除对象时,它将被释放,因为它不再保留。如果您不在该行中释放它,它将被保留两次。一次是因为你的分配,另一次是因为数组。从数组中删除会降低保留计数。但它会永远挂起,因为它不是 0。 - 当你从数组中删除它时,你可以释放它。但该代码将比发布后引用更令人困惑。所以你永远不应该做那样的事情。 在我的仪器输出的原件中添加了截图。这真的让我感到困惑:)

以上是关于可以在这个例子中解释代码流吗??内存泄漏?在哪里?的主要内容,如果未能解决你的问题,请参考以下文章

请解释一下“内存泄漏”,这个问题会有啥影响

内存泄漏检测

内存泄漏典型例子

c++中的动态二维数组和内存泄漏

这里的内存泄漏在哪里?

内存泄漏检测