首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >内存泄漏的Addsubview和dealloc (retainCount)

内存泄漏的Addsubview和dealloc (retainCount)
EN

Stack Overflow用户
提问于 2012-06-14 15:26:19
回答 1查看 1.2K关注 0票数 0

在添加到视图后,我正在检查子视图的retainCount。代码是:

代码语言:javascript
复制
- (void) loadView{
    //...
    toolbar = [[UIToolbar alloc] initWithFrame:nil];
    [[self view] addSubView:toolbar];
}

- (void) dealloc{
    NSLog(@"count=%d", [toolbar retainCount]);   // count=2
    [toolbar removeFromSuperView];
    NSLog(@"count=%d", [toolbar retainCount]);   // count=1
    [toolbar release]
    NSLog(@"count=%d", [toolbar retainCount]);   // count=1
    toolbar = nil;
    NSLog(@"count=%d", [toolbar retainCount]);   // count=0
}

从dealloc{}中的代码中,我有一些问题:

1、工具栏的第一个日志retainCount为2,因为工具栏在初始化并添加到自身视图后,保留计数将变为2。

2 .在工具栏removeFromSuperView之后,retainCount将变为1。

工具栏调用release方法后,retainCount仍然是1,不能变为0。在我的选项中,由于超级视图仍然是工具栏(自身视图不是释放),所以工具栏不能重新使用为0。

4、如果调用设置为nil的工具栏,则retainCount为0。这个日志是无用的。

我的问题是:

A)工具条调用removeFromSuperView和release接口,结果是一样的,工具条retainCount只会变成1,所以如果我只用它们来测试代码,结果是一样的。那么,我是否可以得出结论,用户只能调用每个API都是OK的?

B)从苹果文档中,子视图被添加到自身视图中,自身视图仍然是工具栏句柄,所以在dealloc方法中,如果不调用viewDidUnload,工具栏retainCount不能减少到0。如果内存不足,系统会减少无用的视图,并调用viewDidUnload方法,它会自动将工具栏的retainCount减少到0。所以在dealloc方法中,我是否应该将工具栏设置为nil。如果我将工具栏设置为空,我会感到困惑,当调用viewDidUnload方法时,工具栏是否会缩小?有没有内存泄露?

谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-06-14 15:57:07

首先,如果你的代码反映了你的真实代码,那么你的dealloc方法就有一个大问题:

代码语言:javascript
复制
- (void) dealloc{
   [toolbar removeFromSuperView];
   [toolbar release]
   toolbar = nil;
}

您不能调用[super dealloc]。如果不调用super,self.view将永远不会被释放(并最终被释放)。

这应该会修复您的内存泄漏(至少部分修复):

代码语言:javascript
复制
- (void) dealloc{
    [toolbar release];
    [super dealloc];
}

您可以注意到,我删除了对removeFromSuperView的调用,因为这是在self.view实际释放时自动为您完成的,因此您不需要自己执行此操作。在任何情况下,调用removeFromSuperView也不会导致任何问题。

关于您的问题,我假设您的toolbar属性被声明为retain (根据您提交的代码,这是我最敏感的假设)。

如果toolbar是属性的retain子级,那么为其分配新创建的视图的正确方法是:

代码语言:javascript
复制
 toolbar = [[[UIToolbar alloc] initWithFrame:nil] autorelease];

请注意autorelease;如果没有它,您的保留/释放呼叫将受到影响。这就解释了为什么您需要先调用release,然后在dealloc中nil属性:

代码语言:javascript
复制
- (void)dealloc {
 ...
    [toolbar release]
    toolbar = nil;
 ....
}

通过这样做,您将释放toolbar两次;但是,由于您在分配给retain属性时没有使用autorelease,因此这将产生正确的结果。

a)工具条调用removeFromSuperView和release接口,结果是一样的,工具条retainCount只会变成1,所以如果我只用它们来测试代码,结果是一样的。那么,我是否可以得出结论,用户只能调用每个API都是OK的?

正如我所说的,您不需要直接调用removeFromSuperView来获取在dealloc时发布的子视图,因为self.view将为您做这件事。如果您想要删除一个子视图,同时保留superview (假设您显示了一个标签,然后将其删除),那就是另一回事了;在这种情况下,您需要同时调用这两种方法,否则就会发生泄漏。

b)从苹果文档中,子视图被添加到自身视图中,自身视图保留了工具栏句柄,因此在dealloc方法中,如果不调用viewDidUnload,则工具栏retainCount不能被减少到0。如果内存不足,系统会减少无用的视图,并调用viewDidUnload方法,它会自动将工具栏的retainCount减少到0。所以在dealloc方法中,我是否应该将工具栏设置为nil。如果我将工具栏设置为空,我会感到困惑,当调用viewDidUnload方法时,工具栏是否会缩小?有没有内存泄露?

如果我正确理解了您的疑问,关键是如果您将toolbar属性发送给viewDidUnload中的nil,那么当调用此方法时(无论是显式删除视图还是发出内存警告),您的子视图都将被正确处理;如果此后调用控制器的dealloc,则您的属性已经有了一个nil值,因此释放它不会有任何效果(但这很好,因为它已经在viewDidUnload中释放了)。

另一方面,如果您没有在viewDidUnload中释放您的属性,那么发生的情况是,如果视图在内存警告后再次显示,那么loadView/viewDidLoad将被再次调用;但是在这种情况下,当您创建工具栏子视图并将其引用分配给toolbar属性时(假设它是retain类型),那么较旧的对象将自动为您释放,因此您不会有任何内存泄漏;发生的情况是您使用的内存比您可以使用的内存多了一点(因为工具栏直到再次创建self.view时才被释放)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11028512

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档