【问题标题】:Release in iPhone在 iPhone 上发布
【发布时间】:2023-03-31 02:10:01
【问题描述】:

每当我读到如何避免内存泄漏时,我总会遇到一个概念: "分配的数量必须等于释放的数量"。

但我遇到了一个概念,我们需要多个版本。比如我以前的做法是这样的:

(NSString*) func1
{
    NSString* result = [[NSString alloc] initWithFormat:@"Test String"]];
    return result;
}

(void) func2
{
    NSString* temp = [self func1];
    [temp release];
}

但是我遇到了一个保留计数的概念,它表示在上述情况下,不会为字符串释放内存,因为字符串的保留计数最后为 1。所以正确的做法是

(NSString*) func1
{
    NSString* result = [[NSString alloc] initWithFormat:@"Test String"]];
    [result autorelease];
    return result;
}

(void) func2
{    
    NSString* temp = [self func1];
    [temp release];
}

所以现在我有两个释放内存的版本,这与我在大多数博客上读到的上面的句子“分配的数量必须等于释放的数量”相矛盾。

我对上述内容有点困惑。因为如果我在第一个函数中自动释放字符串并想在第二个函数中长时间使用字符串,如果释放池在两者之间被刷新怎么办,另一方面如果我不使用自动释放它仍然会阻塞内存.

那么正确的做法是什么。

【问题讨论】:

    标签: iphone objective-c


    【解决方案1】:

    在您调用 alloc 时,返回的任何内容都将具有 1 的 retainCount。在该对象上调用 release 将导致它被释放(它的 retainCount 将下降到 0)。那么,在您的第一个示例中,func2 的第二行将释放您从func1 收到的NSString*,并且您的内存管理工作已经完成。

    在第二个示例中,您将func1 中的result 扔到当前的自动释放池中,这将导致它在池耗尽时被释放。一旦该对象被放入池中,您不希望尝试管理该对象的内存 - 这不再是您的责任。

    如果您想生成字符串并保留一段时间(例如,通过几个自动释放池的生命周期),我会推荐第一种内存管理形式。

    【讨论】:

    • 非常正确,除非您在自动释放后保留某些内容,您有责任在每次保留对象时释放它(或再次自动释放)。一次自动释放不会免除您的所有责任:)
    【解决方案2】:

    正确的做法是这样的:

    (NSString*) func1 {
        NSString* result = [[NSString alloc] initWithFormat:@"Test String"];
        // retaincount == 1
        return [result autorelease];
    }
    
    (void) func2 {
        NSString* temp = [self func1];
        // retaincount == 1
        // temp is autoreleased, therefore no [release] is necessary.
    }
    

    自动释放是在运行循环结束时自动完成的,这意味着当你的代码正在做某事时它不能被清空。 -> 您拥有的代码是安全的。 这不适用于多线程应用程序!

    【讨论】:

      【解决方案3】:
      (NSString*) func1
      {
          NSString* result = [[NSString alloc] initWithFormat:@"Test String"]];
          return result;
      }
      

      [结果retainCount]为1

      (void) func2
      {
          NSString* temp = [self func1];
          [temp release];
      }
      

      [临时保留计数] 为 0

      不需要自动释放。

      来自Memory Management Rules

      这是基本规则:

      如果您使用名称以“alloc”或“new”开头或包含“copy”的方法(例如,alloc、newObject 或 mutableCopy)创建对象,或者向其发送保留消息。您有责任放弃使用 release 或 autorelease 拥有的对象的所有权。任何其他时间您收到一个对象,您都不能释放它。 以下规则源自基本规则,或处理边缘情况:

      作为基本规则的推论,如果您需要将接收到的对象作为属性存储在实例变量中,则必须保留或复制它。 (对于弱引用,这不是真的,在“对象的弱引用”中有描述,但这些通常很少见。) 接收到的对象通常保证在接收它的方法中保持有效(例外包括多线程应用程序和一些分布式对象情况,但如果您修改接收对象的对象也必须小心)。该方法也可以安全地将对象返回给它的调用者。 需要时将保留与释放或自动释放结合使用,以防止对象因消息的正常副作用而失效(请参阅“共享对象的有效性”)。

      autorelease 仅表示“稍后发送发布消息”(有关稍后的一些定义,请参阅“自动释放池”)。

      【讨论】:

      • 在两个单独的函数中使用 [retain] 和 [release] 是很危险的,因为很容易忽略一个 retain 或 release。你应该总是返回自动释放的对象,除非方法是 -copy 或 +alloc。
      【解决方案4】:

      一般来说,我觉得对返回值进行保留会更安全,比如“func 2”中的那个:

      (NSString*) func1 {
          NSString* result = [[NSString alloc] initWithFormat:@"Test String"];
          return [result autorelease];
      }
      
      (void) func2 {
          NSString* temp = [[self func1] retain];
          // Do something with temp
          [temp release];
      }
      

      这是不必要的吗?我知道在这个例子中“temp”只是一个局部变量。但它可能是一个实例变量,可能需要保留。

      【讨论】:

      • 是的,没有必要,直到当前运行循环结束,或者当前的 NSAutoreleasePool 被耗尽,自动释放的对象才会被释放。除非您明确要求管理自己的 NSRunLoop 或 NSAutoreleasePool,否则您是安全的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-04
      • 1970-01-01
      • 1970-01-01
      • 2012-08-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多