使用alloc / retain / release的可能方案?

时间:2010-07-23 02:40:29

标签: objective-c memory-management retain

我已经使用ojective近一个星期了,我主要是一个c ++编码器。在我阅读了Apple的内存管理指南之后,我尝试将c ++中的内存使用方式带入目标c ...我试图总结这些场景,我想如果我遵循这些说明,我不会犯错误。如果我错了,请告诉我。)

我会尝试不使用自动释放,个人来说,通过使用自动释放,在某个自动释放池耗尽之前可能总会有一些冗余内存。我只会使用release,这可以确保我的应用程序在任何时候都使用最少的内存。

用我自己的话说,苹果说的另一件事是:每次我添加一个retain / alloc / copy,我都应该在某处添加发布

以下是我总结的所有情景:

  1. 在同一个函数中: alloc 一个对象,使用它,然后发布

  2. 在类的 init 函数中, alloc 一个对象,在该类的 dealloc 函数中,发布对象

  3. 当需要拥有指针时,应该保留类的方法中的输入指针(假设方法A ),然后< em> release 该类的 dealloc 函数中的指针。

    我发现在目标c中使用 retain 的时间与在c / c ++中使用 memcpy 的时间相同,所以我采用 retain < / em>作为“内存高效副本”

    如果输入保留指针要设置为成员指针变量,则应首先释放成员指针。 所以在案例[3]中,类的 init 中的 alloc 方法A 中的 release 配对, 并且方法A 中的保留 dealloc

  4. 中的发布配对
  5. 返回指针作为返回值。老实说,当我使用c ++时,我从未做过这样的事情。如果要返回一个成员指针就可以了,因为有人会照顾它:

    -(UIButton*) getTheButton() {
        return theButton;
    }
    

    但是返回指向本地分配对象的指针真的很糟糕:

    -(UIButton*) getTheButton() {
        UIButton* myButton = [[UIButton alloc] init];
        return myButton; //TERRIBLE!
    } 
    

    有人可能会说我应该在这种情况下使用自动释放,但我只是想通过使用它来绕过该解决方案:我只会返回成员指针,或者我不会返回指针,我只会对给定的输入指针进行操作。 / p>

    -void operateOnTheButton(UIButton* button) {
        [button release];
        button = [[UIButton alloc] init];
    } 
    
  6. 所以,如果我按照上面的内存使用说明,请告诉我是否有任何问题。

    谢谢:D

5 个答案:

答案 0 :(得分:9)

有一个重要的情况是必须使用autorelease。如果您分配/保留/复制一个对象,然后将其返回到拥有该对象的其他代码,但您不能release它,因为其他代码需要使用它(或者您不会回来的。)

在这种情况下,必须通过发送autorelease消息来对该对象的发布负责,从而确保它最终会被释放。这正是NSString的stringWithString:这样的基础方法所做的。您没有release从此方法获得的字符串对象,因为您没有分配/保留/复制它,但如果该方法没有为您自动释放它,它将在{{1}之后存活并成为内存泄漏。

确保您了解引用计数的工作原理。 [pool drain]递减对象的引用计数。当计数达到0时,对象被销毁。 releasealloc创建一个引用计数为1的对象。copy将接收对象的引用计数增加1.对于每个alloc / retain / copy,必须有一个retain }。 1上,1下。

因此,当您返回您创建的对象时,将控制传递给被调用者,您会使1到1的等式失衡,因为您无法release它。这就是release的原因。它不会减少接收者的ref计数器,所以它不会被破坏,但是当池耗尽时,池中的每个对象都会收到一条autorelease消息,它已经收到了每个release,恢复平衡(除非有意保留一个对象,以便它能够在排水中存活,在这种情况下被调用者需要稍后autorelease

至于第4点,如果你release,你的第二个例子就没问题,在基础课中这个例子比比皆是。 NSString,NSArray,NSDictionary等每个数据类都有返回本地分配的对象指针的方法。它们的格式通常为autorelease,如thisWiththat:stringWithstring:。后者将分配一个字典对象,用文件内容填充它,自动释放它,并返回一个指向你的指针。它被称为工厂功能。 obj-c中的常见模式,也是java。

您是第三个代码示例,稍后会导致运行时错误。您正在发布一个您不拥有的对象。所有者不会指望你dictionaryWithContentsOfFile:它可能意味着它会收到太多release个消息,从而导致运行时错误。如果你没有分配/保留/复制它,你就不拥有它,所以你不应该发布它。

答案 1 :(得分:2)

自动释放部分不正确。如果您执行的工厂方法不是以alloc / retain / copy开头的。你必须自动发布它。调用者不会创建对象,因此调用者不能也不应该释放它。因此,如果调用者想要做某事并确保那里的对象,调用者必须自己保留它们。

好的解决方案是:

-(UIButton*) getTheButton() {
    UIButton* myButton = [[UIButton alloc] init];
    return [myButton autorelease];  // if you don't do autorelease, memory will leak
} 

然后在来电者中:

- (void)caller {
  UIButton *button = [[self getTheButton] retain];
}

你不能这样做:

-void operateOnTheButton(UIButton* button) {
    [button release];
    button = [[UIButton alloc] init];
} 

原因:operateOnTheButton没有自己的按钮,它不应该释放按钮。如果我发给你一个按钮然后在通话后会发生什么,我有另一个按钮。 operateOnButton不分配/保留/复制参数。它没有权利发布它。 它可能会给你带来一些问题:

1 / EXEC_BAD_ACCESS:当您在不拥有该对象的方法内发布时,某人仍可能使用它

2 /内存仍然泄漏:释放并不意味着您立即删除内存。你只需将retainCount减1.这意味着如果传递按钮对象时retainCount为2,释放它只会使你的retainCount为1,不会删除对象的内存

3 /您的按钮对象也是泄漏:没有人可以确保您的按钮对象被释放。你拥有它,所以你必须自己释放它,否则,按钮对象是泄漏

答案 2 :(得分:1)

  1. 这种情况很正常,但有些人(包括我自己)喜欢在与alloc相同的行上自动发布,以避免意外忘记释放。

  2. init 通常会调用alloc。在对象上创建时,首先调用alloc,然后在新分配的实例上调用init

  3. 这种情况非常正确。但是,保留不会复制。

  4. 在Objective-C中,对象总是由它们的指针引用,这与C ++不同。如果您正在编写一个返回字符串的方法,那么您将返回NSString*,而不是NSString结构本身。

  5. 以下代码片段实际上会导致内存泄漏:

    -(void) operateOnTheButton:(UIButton*)button {
        [button release];
        button = [[UIButton alloc] init];
    } 
    

    button是一个局部变量,当它超出范围时,它会泄漏,因为它尚未被释放。我不太确定这个operateOnTheButton:方法应该做什么。

答案 3 :(得分:0)

为什么要避免自动释放?这是它应该做的方式......

另外,一些建议:

许多人在iPhone上做的一个错误是在UIViewController的viewDidLoad方法中分配内存,然后在dealloc方法而不是viewDidUnload方法中释放它。

始终考虑可以多次加载视图。

答案 4 :(得分:0)