【问题标题】:Objective C memory problemObjective C 内存问题
【发布时间】:2010-07-26 14:21:15
【问题描述】:

我有2个场景,我想知道哪种方式是正确和更好的?


-(Employee*) getCustomEmployee{

  Employee *emp = [[Employee alloc]init]; // no autorelease here
  //do something with emp

  return emp;
}

-(void) process{

   Employee *emp = [self getCustomEmployee];
   //do something with emp

   [emp release]; //release emp object here

}

-(Employee*) getCustomEmployee{

  Employee *emp = [[[Employee alloc]init]autorelease]; //NOTE: autorelease here 
 //do something with emp

  return emp;
}

-(void) process{

   NSAutoreleasePool *pool = [[NSAutoReleasePool allc]init];

   Employee *emp = [self getCustomEmployee];
   //do something with emp

   [pool release];

}

【问题讨论】:

    标签: iphone objective-c iphone-sdk-3.0 ipad


    【解决方案1】:

    第二个是更好的做法,但仍然不正确。您正在编写一个不应创建内存的吸气剂。相反,它应该返回对已创建内存的引用。最好将其重命名为工厂方法“customEmployee”并使用自动发布,因为这是 Apple 鼓励的命名约定,在其他 API 调用中也可以找到。您还可以有一个不自动释放的 createCustomEmployee。命名约定在这里很重要。

    【讨论】:

      【解决方案2】:

      如果您渴望遵循 Cocoa 的约定,您应该在 this 文章中明确回答您的问题

      【讨论】:

        【解决方案3】:

        撇开根据 Apple 命名约定不应该在这些方法前加上“get”这一事实,第二个版本更正确,因为它符合 Apple 的内存管理规则。

        您可以通过在方法名称前加上“新”前缀来使第一个示例更好,例如newCustomEmployee。但是,使用 new 有点过时了。

        【讨论】:

          【解决方案4】:

          我认为第二个不需要 AutoreleasePool。我很确定有一个默认值。因此,除非您的处理方法非常密集,否则池不是必需的。

          我会说自动释放是要走的路。

          假设您必须在代码中的不同位置调用 getCustomEmployee 方法。 每次调用此方法时,都必须记住释放 Employee。

          【讨论】:

            【解决方案5】:

            自动发布的方式更为典型,但您可以使用任何一种方式,但有一点需要注意:

            • 如果要返回调用者需要释放的对象,则应将例程命名为 createCustomEmployee 而不是 getCustomEmployee,以遵循 Cocoa 命名约定。 (名称中带有createalloc 的例程返回一个必须释放的对象)。

            【讨论】:

            • -1 不,create 用于 Core Foundation,而不是 Cocoa。 Cocoa中的规则是以alloc或new开头的方法,包含copy和retain的方法。
            【解决方案6】:

            第二个更好。

            来自Memory Management Programming Guide

            • 您拥有自己创建的任何对象。
            • 您使用名称以“alloc”或“new”开头或包含“copy”的方法“创建”对象(例如,alloc、newObject 或 mutableCopy)。

            由于您的 getter 方法不符合任何这些条件,因此不应使调用者隐式成为返回对象的所有者。如果调用者想要拥有它,则应在返回值上显式调用 retain

            话虽如此,您的代码中不需要NSAutoreleasePool,因为默认情况下,运行循环已经有一个池。有了这个,以下就足够了:

            - (Employee*) getCustomEmployee {
               Employee *emp = [[[Employee alloc] init] autorelease];
               // do something with emp
               return emp;
            }
            
            - (void) process {
              Employee *emp = [self getCustomEmployee];
              // do something with emp
            }
            

            其他回答者说您不应该在 getter 中分配新对象。我不同意这一点。在许多情况下,按需创建对象是一种很好的做法。特别是当您拥有可能永远不需要分配的资源密集型对象时。只要遵守所有权规则,在 getter 中分配新对象是完全可以接受的。

            在这种情况下,如果员工可以在多个调用者之间共享,那么您可能需要考虑延迟初始化。以下代码假定您有一个名为 _employee 的实例变量(objective-c 术语中的 ivar)。

            - (Employee*) getCustomEmployee {
               @synchronized(self)
                  if (!_employee) {
                     _employee = [[Employee alloc] init];
                  }
               }
               return _employee;
            }
            
            - (void) dealloc {
               [_employee release];
            }
            
            - (void) process {
              Employee *emp = [self getCustomEmployee];
              // do something with emp
            }
            

            在这种情况下,所有权属于创建它的对象,因此它必须在将来的某个时间释放内存。释放拥有的对象的自然位置是对象本身被释放的时候。当这种情况发生时,dealloc 方法将被调用,因此我们可以进行清理。

            【讨论】:

              【解决方案7】:

              通常是第二个——在 Objective-C 中,您通常从方法返回自动释放的对象,除非它是 initcopy 方法。

              【讨论】:

              • 其实是以alloc或new开头的方法,包含copy和retain的方法。
              • init 方法几乎总是与alloc 方法结合使用(事实上,在规范的Objective-C 中总是)。我很少抱怨投反对票,但你在这里非常迂腐。
              • 不,我不是。阅读内存管理规则。在任何情况下,init 方法都不会与 init 方法中的 alloc 一起使用。
              • 当然。但是alloc/init 几乎只作为一对使用,所以说init 方法返回一个自动释放的对象并不是完全不正确的。值得反对并没有真正的错误。这是经验丰富的 ObjC 开发人员熟悉的知识。
              猜你喜欢
              • 2011-07-04
              • 1970-01-01
              • 1970-01-01
              • 2011-05-11
              • 2011-03-13
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多