1

方法removeFromSuperView如何工作? 我的记忆问题不好访问时,我想重新初始化视图内存管理

- (id)init { 
    if (!(self = [super init])) 
     return nil; 

    _mainView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
    UIButton *reInitButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f,0.0f,90.0f,35.0f)];  
    [reInitButton addTarget:self action:@selector(buttonDidTapped:) forControlEvents:UIControlEventTouchUpInside]; 
    [[self view] addSubView:_mainView]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
    [_mainView release]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 

    return self; 
} 

- (void)buttonDidTapped:(id)sender { 
    [_mainView removeFromSuperView]; //crash during second times press the button 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
    _mainView = [[UIView alloc] initWithFrame[[UIScreen mainScreen] bounds]]; 
    [[self view] addSubView:_mainView]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
    [_mainView release]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
} 

我的NSLog每一个时代有任何保留或页头或释放关键字。结果非常奇怪。

//init 
retainCount : 1 
retainCount : 2 
retainCount : 1 
//1st time pressed button 
retainCount : 1 //remove super view didn't decrease 
retainCount : 2 
retainCount : 1 
//2nd time pressed button 
retainCount : 0 //crash. Memory bad access 

奇怪的是它为什么没有在第一次按下时崩溃?

回答

3

我觉得你的问题是在这里:

[_mainView release]; 

您已经降到大家参考_mainView,然而,以我的阅读,这是一个成员变量,你会保持周围,并继续在调用方法。这是无效的。一旦你调用了-release,你基本上已经告诉系统你不会再使用该对象,并且不能对指向该对象的陈旧指针做任何有用的操作,就像你在调用-removeFromSuperView时做的那样之后。

如果你想继续保留_mainView并在其上调用代码,你需要保留一个参考。也许你应该将发布版本移到你的对象的-dealloc方法中。或者,您可以在按钮方法中使用-release,并在下次需要时重新创建新视图。

作为一个有用的提示,很多程序员喜欢在释放它们之后将对象重置为NULL(或objC-speak中的nil),以提醒您不能再次使用该对象。如果你-release的东西,你最好是这个意思。

最后,我建议你谷歌术语“引用计数”,并阅读它;这是一个比NSObject更具通用性的成语,它可能会帮助您思考基本知识,以及如何用另一种语言(如C,C)来实现此功能。这有助于您更好地理解引用计数对象。

+0

+1在这种情况下设置为零。 – 2011-05-15 05:33:51

+0

请注意,将release释放到'dealloc',并且仍然在按钮的动作中创建新视图将导致泄漏。 – 2011-05-15 05:42:45

+0

@Josh Caswell - 是的,的确如此。这是'nil'事情派上用场的地方...... if(_mainView)[_mainView release]; _mainView =/* ... * /;'但是你仍然希望在dealloc中有一个版本。 – asveikau 2011-05-15 05:45:33

3

永远不要使用RETAINCOUNT。对不起,把它放在帽子里,但我无法弄清楚为什么人们仍在使用它。这是内存管理的一个错误参考。使用仪器或类似的东西。

+0

ok我不会再使用它了,它有什么问题,我想我已经发布了它的需要,但它仍然崩溃。如果我在buttonDidTapped中注释了这个版本:它没有崩溃,但我认为它被泄露 – Lunayo 2011-05-15 05:18:30

+0

观察引用计数(这是一个比“retain count”更标准的术语,所以也许google了解它)在'-retain'或'-release'等特定方法的实现之外。问题是如果refcount为零,则支持该对象的内存(包括支持refcount本身的内存)被释放,因此在放弃引用后访问对象是不安全的,出于同样的原因,您无法触及'free'后的缓冲区。其他代码片段也可以保留并释放内存,并且你不能依赖他们的行为。 – asveikau 2011-05-15 05:23:41

+0

@Lunayo:[retainCount认为有害](http://stackoverflow.com/questions/5784084/)关于该主题的其他有趣的解读:[1](http://stackoverflow.com/questions/5155559/)[2] (http://stackoverflow.com/questions/5483357/)[3](http://stackoverflow.com/questions/5391479/)[4](http://stackoverflow.com/questions/3354724/)[5 ](http://stackoverflow.com/questions/5220902/) – 2011-05-15 05:25:40

2

此时您不应该访问_mainView。这可能很难解释,请耐心等待。我们将计算,但不是绝对保留数,只是您的代码对该对象的声明。

你为一个对象,并在点其分配存储器与_mainView

_mainView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 

您有1个如权利要求所有权的到该对象。当你将它作为另一个视图的子视图添加时,该视图同样会声明所有权,但那不是你的,而是视图的。它使_mainView中的对象继续存在的事实是一个意外,你不应该依赖它。然后你释放对象:

[_mainView release]; 

你已经放弃自己的所有权声明 - 你现在有0索赔,你不再尝试访问该对象。你不拥有它。同样,由于另一种观点正在使用它,以及你仍然有一个指向它的事实,它仍然存在的事实是事故*,你不应该依赖它们。

当谈到时间来处理你按下按钮,那么,你所访问过,你有没有所有权的对象:

[_mainView removeFromSuperView]; 

,这会导致系统崩溃,这可能无法预料,但它是不无道理。通过让你的所有权声明变为0,你告诉系统“我不再需要这个对象,在这之后我不会再访问它,如果它消失了,我不会受到影响。”实际上,虽然,你需要需要它留下来,你需要访问它。

你应该做的,那么,是招行:

[_mainView release]; 

的按钮动作里面,调用removeFromSuperview之后。


*其中的第二个可以通过设置_mainView = nil;你释放后,在这种情况下是可以避免的,但不会解决更大的问题。