命名方法的简单规则,与ARC命名约定兼容

时间:2014-03-20 10:04:21

标签: objective-c memory-leaks automatic-ref-counting naming-conventions class-method

我很难理解ARC的命名约定。我一直用ARC编码,我猜这就是原因。

1。类方法

  • 我应该为以下方法选择什么名称?
  • 这两个名字之间在内存管理方面有什么不同?

这个名字:

+ (MyObject *)newObjectFrom:(MyObject *)anObject 
                withOptions:(NSDictionary*)options
{
    MyObject * newObject = [anObject copy] ;
    [newObject modifyWith:options] ;
    return newObject ;
}

还是这个名字?

+ (MyObject *)objectFrom:(MyObject *)anObject
             withOptions:(NSDictionary*)options
{
    MyObject * newObject = [anObject copy] ;
    [newObject modifyWith:options] ;
    return newObject ;
}

2。实例方法

  • 我应该为以下方法选择什么名称?
  • 这两个名字之间在内存管理方面有什么不同?

这个名字:

- (MyObject *)newObjectwithOptions:(NSDictionary*)options
{
    MyObject * newObject = [self copy] ;
    [newObject modifyWith:options] ;
    return newObject ;
}

还是这个名字?

- (MyObject *)objectwithOptions:(NSDictionary*)options
{
    MyObject * newObject = [self copy] ;
    [newObject modifyWith:options] ;
    return newObject ;
}

2。命名方法的简单规则

在命名方法时是否有一条基本的简单规则?

基本的,简单的",我的意思是

  • 类似于" strong的规则,当对象属于类"," weak时,该对象刚被此类引用, (因此)由另一个班级拥有";

  • (和/或)没有ARC时没有引用内存管理的规则;

  • (和/或)不使用" autorelease"," release"等字词的规则。

7 个答案:

答案 0 :(得分:5)

方法名称 非常重要。关于ARC如何解释方法名称的官方文档可以在method families部分的clang ARC文档中找到。

答案 1 :(得分:4)

当里维拉说方法名称并不重要时,他可能会遵循他的经验:它始终有效。这是正确的。你是对的,你可能不理解方法名称的作用,因为你一直使用ARC。那么最重要的是什么呢?

我在这个答案的最后添加了一个概要来说明MRR的问题。正如您在那里看到的那样,您不必像使用MRR一样使用ARC命名规则。

为了给您更详细的解释,您必须了解使用MRR会发生什么:

在ARC之前,必须手动进行内存管理。这样做他必须知道,返回值具有什么样的所有权。长话短说,人们必须知道,他是否必须释放一个返回的物体:

规则1 :您没有自动拥有方法返回的对象。如果您想要保留它,请保留它并在完成后将其释放。

id object = [[object methodThatReturnsAnObject] retain]; // I want to hold it
…
[object release]; // Done with it

id object = [object methodThatReturnsAnObject]; // I do not want to hold it
…
// I do not release it

进行深入分析,您会发现有时会出现问题。 (对象释放是副作用。)但这是基本方法。

这样做的好处是可以在本地处理保留 - 释放对(在复合语句中),并且很容易遵循对象的所有权。

规则2 :但是当第一次创建对象时,这不起作用:消息的发送者总是持有它。否则它将被立即销毁(=在发件人有机会保留它之前。)所以还有一个额外的规则:

如果返回对象的类方法的名称以alloc,init或new开头,则必须处理返回的对象,因为对其执行了保留。或者用一个词来说:所有权转移:

id object = [Class allocOrInitOrNewMethod];
…
[object release];

-retain明确取得所有权后,alloc–init…new…会隐式转让。

所有其他方法的行为与规则1相同。

规则3 :有时你需要一个自动释放池。 为了使ARPs的优势可见,想到这段代码:(这没用,只是为了演示问题

案例1.1:

Person *person = [[Person alloc] initWithName:…]; // Ownership transfer, release person, when you are done
NSString *name = [person name]; // the name object is hold by the person object only
[person release]; // I do not need the person object any more
[name doSomething]; // Crash: The person was the only object holding the name

另一个问题:

案例2.1:

Person *person = [[Person alloc] initWithName:…]; // Ownership transfer, release person, when you are done
if (…)
{
   return; // break, continue, goto
}
…
[person release];

因为永远不会到达最后一行,所以永远不会释放该对象。

您可以使用自动释放方法修复它。只要控制流返回到运行循环,移动到ARP的对象就会存在。所以它贯穿于每一种方法,通过方法返回等等。要明确地做到这一点:

案例1.2:

Person *person = [[[Person alloc] initWithName:…] autorelease]; // No ownership transfer, persons belongs to the ARP
NSString *name = [person name]; // the name object is hold by the person object only
[name doSomething]; // No Crash: The person object holding the name object is still alive

案例2.2:

Person *person = [[[Person alloc] initWithName:…] autorelease]; // No ownership transfer, prsons belongs to the AR.
if (…)
{
   return; // break, continue, goto
}
…
// No release necessary.

因为一个人懒得输入这么长的消息链,所以发明了便利分配器来为你做这件事:

+ (Person*)personWithName:(NSString*)name
{
   return [[[self alloc] initWithName:name] autorelease];
}

结果:

案例2.3:

Person *person = [personWithName:…]; // No ownership transfer, persons belongs to the AR.
if (…)
{
   return; // break, continue, goto
}
…
// No release necessary.

你可以用吸气剂做同样的事情:

- (NSString*)name
{
   return [[_name retain] autorelease];
}

所以我们在一天结束时有简单的规则:

规则1:如果你想在内存中保留一个返回的对象,请保留它 - 并在你不再需要它时释放它。

规则2:如果类方法的名称以alloc,new或init开头,则将其视为隐式retain(因此,当您完成对象时,将其释放。)

规则3:为方便起见,使用-autorelease延迟返回对象的重新分配。

<强>梗概:

Alloc-init创建

// MRR:
Person *person = [[Person alloc] initWithName:@"Amin"];
…
[person release]; // You create it, you release it

// ARC:
Person *person = [[Person alloc] initWithName:@"Amin"];
…

新创作者

// MRR:
Person *person = [[Person newPersonWithName:@"Amin"];
…
[person release]; // You create it, you release it

// ARC:
Person *person = [[Person newPersonWithName:@"Amin"];
…

便利分配器

// MRR:
Person *person = [[Person personWithName:@"Amin"]; // Autoreleased
…

// ARC:
Person *person = [[Person personWithName:@"Amin"];
…

正如您所看到的,使用ARC创建对象的三种方式没有区别。所以里维埃拉是对的,当他说这不重要了。但在幕后,最后一种方式是不同的,因为它将对象移动到ARP。

与此方法的实现相同:

实施新的分配器

// MRR
+ (Person*)newPersonWithName:(NSString*)name
{
    return [[self alloc] initWithName:name];
}

// ARC
+ (Person*)newPersonWithName:(NSString*)name
{
    return [[self alloc] initWithName:name];
}

实施便利分配器

// MRR
+ (Person*)personWithName:(NSString*)name
{
    return [[[self alloc] initWithName:name] autorelease];
}

// ARC
+ (Person*)personWithName:(NSString*)name
{
    return [[self alloc] initWithName:name];
}

使用ARC,两种方法的实现方式相同。

- &GT; 您不再需要任何此规则。 ARC关心您。

特别是你不再需要便利分配器了,因为没有什么不方便了。 (即使它们在运行时进行了优化,仍然存在最小的运行时间损失。)我不再实现便捷分配器,而是新的分配器。

但ARC必须与MRR兼容。所以它记得所有规则。为了使您的代码对其他人可读,您也应该重复此规则。但是,当然,现在便利分配器和新分配器的实现是逐位相同的 - 其余部分由ARC完成。

答案 2 :(得分:2)

将代码从MRC转换为ARC以及与ARC代码中的MRC代码进行互操作时,方法命名约定非常重要。
Apple指南说,仅使用“ARC代码”,命名约定“不太重要”,但这并非100%正确。

例如(这只是一个例子,我认为还有很多其他例子),请看this project

我调用了release-autorelease调用来记录它,你可以看到差异:

当方法以特殊命名(例如“new”)开头时,ARC返回一个保留计数为+1的对象,该对象由释放调用平衡。
使用差异名称时,ARC返回AUTORELEASED对象。 (查看NSLog调用)

在循环中分配大量对象的代码中,这可能是一个很大的不同。在这种情况下,程序员应该创建一个自动释放池。

因此,在使用仅ARC代码时,命名约定不太重要。

答案 3 :(得分:0)

我不能100%了解命名方法的所有细节100%,因为每种情况都有不同的情况。但我认为Apple文档中的这篇文章会对你有帮助。 https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Conventions/Conventions.html

答案 4 :(得分:0)

首先,内存管理与您为方法或类选择的名称无关。 换句话说,如果它编译并且您不使用保留关键字或关键方法名称,那么您应该很好。(请参阅编辑说明)

对于1,前面的new在Objective-C中非常罕见,因此最好使用objectFrom:

更好的方法是更准确地了解您正在创造的对象类型。例如:

[NSArray arrayWithArray:]
[NSString stringWithFormat:]

或者在您创建副本的情况下,并假设您正在创建&#34;客户端&#34;对象:

[Client clientWithClient:options:]

实际上并不需要with

2我会选择:

copyWithOptions:

您或多或少地定制[NSObject copy]。我也只实现这个方法并删除现在冗余的1,因为更少的方法更清晰,更容易记录,更容易维护!

如有疑问,只需搜索SDK文档,了解Apple如何命名类似的方法。

修改

在第一段中,我并不是要鼓励不良的命名行为,只是说它们不是您的记忆管理问题的原因。然而,您应该尝试遵循其他答案中指出的命名约定,或者正如我所说的那样,&#34;像Apple那样做#34;。

答案 5 :(得分:0)

我在苹果世界的经验是,像你的例子这样的工厂方法通常会按照惯例包含“创造”。现在使用ARC可能不那么重要,但在过去,在方法或函数签名中“创建”是一种非常肯定的火灾方式,以确保您了解您正在获取所得对象的所有权(由于发布/免费()它)而不是你想要自动释放[NSArray数组],[UIColor colorWith ....]等的实例类型,所以我仍然非常喜欢遵循这个约定。

答案 6 :(得分:0)

  1. ARC给出了以前用于跟踪引用计数职责的命名约定的语义。所以现在编译器使用相同的命名模式来确定方法是否返回保留对象等。请参阅@ JodyHagens&#39;中的链接。使用http://clang.llvm.org/docs/AutomaticReferenceCounting.html#semantics-of-method-families

    回答并继续阅读
      

    alloccopymutableCopynew系列中的方法 - 即除init之外的所有当前定义的系列中的方法 - 隐式返回一个保留对象,就像它们使用ns_returns_retained属性进行注释一样。这可以通过使用ns_returns_autoreleasedns_returns_not_retained属性之一注释方法来覆盖。

    &#34; new家庭&#34;是以&#34; new&#34;开头的消息选择器然后是一个大写字母。所以 {/ 1}}和newObjectFrom:withOptions:之间的内存管理差异,但您可以使用注释来覆盖它(不要去那里),编译器应该抱怨如果你弄错了。

    (实现给定消息选择器的所有方法最好提供相同的引用计数语义。)

  2. 除了@ iRebel_85指出的Apple's article on ConventionsApple has an extensive set of naming guidelines

  3. Google's style guide adds a few more naming guidelines
  4. 这些指南经过深思熟虑,对于使代码更易于理解和协作非常有用。