简体   繁体   English

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

[英]Simple rules for naming methods, compatible with ARC naming conventions

I have difficulties understanding naming conventions of ARC. 我很难理解ARC的命名约定。 I have always coded with ARC, and I guess this is the reason. 我一直使用ARC进行编码,我想这就是原因。

1. Class methods 1.类方法

  • What name should I choose for the following method? 我应该为以下方法选择什么名称?
  • What are the differences, concerning memory management, between theses two names? 这两个名称在内存管理方面有什么区别?

This name: 这个名字:

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

or this name ? 还是这个名字?

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

2. Instance methods 2.实例方法

  • What name should I choose for the following method? 我应该为以下方法选择什么名称?
  • What are the differences, concerning memory management, between theses two names? 这两个名称在内存管理方面有什么区别?

This name: 这个名字:

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

or this name? 还是这个名字?

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

2. Simple rules for naming methods 2.命名方法的简单规则

Is there a basic, simple rule to follow when naming methods? 命名方法时是否要遵循基本的简单规则?

By "basic, simple", I mean 我所说的“基本,简单”

  • a rule similar to " strong when the object belongs to the class", " weak when the object is just referred to by this class, and (thus) owned by another class"; 类似于“当对象属于该类时为strong ”,“仅当该类引用该对象并且(因此)为另一类所拥有时​​”为weak ”的规则;

  • (and/or) a rule that does not refer to the memory management without ARC ; (和/或)不涉及没有ARC的内存管理的规则;

  • (and/or) a rule that does not use words such as "autorelease", "release". (和/或)不使用“自动发布”,“发布”之类的词的规则。

Method names are important. 方法名称重要。 The official documentation of how ARC interprets method names can be found in the clang ARC documentation in the section on method families . 关于ARC解释方法名称的官方文档可以在clang ARC文档的“ 方法系列 ”部分中找到。

When Rivera said that method names are not important, he probably followed his experience: It always works. 当里维拉说方法名称并不重要时,他可能会遵循他的经验:它总是有效的。 And this is correct. 这是正确的。 And you are correct that you probably do not understand the role of method names because you has always used ARC. 而且您是正确的,因为您一直使用ARC,所以您可能不了解方法名称的作用。 So what is the big deal with it? 那么有什么大不了的呢?

I added a synopsis to show the problem with MRR at the end of this answer. 我在此答案的末尾添加了摘要以显示MRR的问题。 As you can see there, you do not have to care about naming rules using ARC the way you had to with MRR. 如您所见,您不必像使用MRR那样关心使用ARC命名规则。

To give you a more detailed explanation, you have to understand what happens using MRR: 为了给您更详细的解释,您必须了解使用MRR会发生什么:

Prior to ARC one had to do memory management manually. 在ARC之前,必须手动进行内存管理。 Doing so he had to know, what kind of ownership a return value has. 为此,他必须知道回报值具有什么样的所有权。 To make a long story short, one had to know, whether he has to release a returned object: 简而言之,必须知道他是否必须释放返回的对象:

Rule 1 : You do not own an object returned by a method automatically. 规则1 :您不拥有方法自动返回的对象。 If you want to hold it, retain it and release it, when you are done with it. 如果要握住它, 在完成后保留并释放它。

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

Doing a deep analysis you can see that there are sometimes problems. 进行深入分析,您会发现有时会出现问题。 (Object deallocation as a side effect.) But this was the basic approach. (对象重新分配是一个副作用。)但这是基本方法。

The advantage of that was that a retain-release pair could be handled locally (inside a compound statement) and it was easy to follow the ownership of an object. 这样做的好处是可以对保留释放对进行本地处理(在复合语句中),并且很容易跟踪对象的所有权。

Rule 2 : But when an object was created the first time this could not work: The sender of the message has always to hold it. 规则2 :但是,当第一次创建对象时,此操作将不起作用:消息的发送者必须始终保留它。 Otherwise it would be destroyed immediately (= before the sender has the chance to retain it.) So there was a additional rule: 否则,它将被立即销毁(=在发件人有机会保留它之前。)因此,还有一条附加规则:

If the name of a class method that returns an object starts with alloc, init, or new you have to handle the returned object as you did a retain on it. 如果返回对象的类方法的名称以alloc,init或new开头,则必须像对待保留对象一样处理返回的对象。 Or in one word: Ownership transfer: 或一句话:所有权转让:

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

As -retain took the ownership explicitly, alloc– , init… , new… transferred it implicitly. 由于-retain明确地取得了所有权, alloc–init…new…隐式转移了所有权。

All other methods behaves like rule 1. 所有其他方法的行为类似于规则1。

Rule 3 : Sometime you need an autorelease pool. 规则3 :有时您需要一个自动释放池。 To make the advantage of ARPs visible think of this code: (It is useless, just to demonstrate the problem 为了使ARP的优势可见,请考虑以下代码:(它无用,只是为了演示问题。

Case 1.1: 情况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

Another problem: 另一个问题:

Case 2.1: 情况2.1:

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

Because the last line is never reached, the object is never released. 因为永远不会到达最后一行,所以永远不会释放对象。

You can repair that with autoreleasing methods. 您可以使用自动释放方法进行修复。 An object moved to the ARP lives as long as the control flow returns to the run loop. 只要控制流返回到运行循环,移动到ARP的对象就会存在。 So it lives through every method, through method return and so on. 因此,它存在于每种方法中,通过方法返回等中。 To do it explicitly: 要明确地做到这一点:

Case 1.2: 情况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

Case 2.2: 情况2.2:

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

Because one has to be too lazy to type such a long message chain, convenience allocators has been invented to do this for you: 因为必须懒得键入这么长的消息链,所以发明了便利分配器来为您做到这一点:

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

With the result: 结果:

Case 2.3: 情况2.3:

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

And you can do the same with getters: 您也可以使用吸气剂做同样的事情:

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

So we at the end of the day we have simple rules: 因此,总而言之,我们有简单的规则:

Rule 1: If you want to keep a returned object in memory retain it – and release it, when you do not need it any more. 规则1:如果要将返回的对象保留在内存中,请保留该对象,然后在不再需要它时将其释放。

Rule 2: If the class method's name starts with alloc, new, or init, think of it as an implicit retain (and therefore release it, when you are done with the object.) 规则2:如果类方法的名称以alloc,new或init开头,则将其视为隐式retain (并在完成对象操作后将其释放)。

Rule 3: Use -autorelease to delay the deallocation of returned objects for convenience. 规则3:为方便起见,请使用-autorelease延迟返回对象的重新分配。

Synopsis: 概要:

Alloc-init creation 创建Alloc-init

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

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

New creator 新创作者

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

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

Convenience allocator 便利分配器

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

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

As you can see, there is no difference for the three ways of object creation using ARC. 如您所见,使用ARC创建对象的三种方式没有区别。 So Riviera is right, when he said that this is not important any more. 所以里维埃拉是对的,当他说这不再重要时。 But under the hood the last way is different, because it moves the object to the ARP. 但是在幕后,最后一种方法是不同的,因为它将对象移动到ARP。

It is the same with the implementation of this methods: 此方法的实现相同:

Implementing a new allocator 实施新的分配器

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

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

Implementing a convenience allocator 实现便利分配器

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

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

Again the implementation for both methods is identical using ARC. 同样,使用ARC,这两种方法的实现方式都是相同的。

-> You do not need it any of this rules any more. -> 您不再需要任何此规则。 ARC cares four you. ARC在乎您四个。

Especially you do not need convenience allocators any more, because there is nothing inconvenient any more. 特别是您不再需要使用便利分配器,因为不再有任何不便之处。 (And even they are optimized at run time, there is still a minimal runtime penalty.) I do not implement convenience allocators any more, but new allocators. (即使它们在运行时进行了优化,运行时的损失也仍然最小。)我不再实现便捷分配器,而是实现新的分配器。

But ARC has to be compatible with MRR. 但是ARC必须与MRR兼容。 So it remembers all that rules. 因此它记住所有规则。 To make your code readable for others you should repeat this rules, too. 为了使您的代码对其他人可读,您也应该重复此规则。 But, of course, now the implementation of a convenience allocator and a new allocator is bitwise identical – the rest is done by ARC. 但是,当然,现在便利分配器和新分配器的实现按位相同–其余工作由ARC完成。

Method naming conventions are important when converting the code from MRC to ARC, and when interoperating with MRC code from ARC Code. 将代码从MRC转换为ARC时,以及与ARC Code中的MRC代码进行互操作时,方法命名约定非常重要。
Apple guide says that with "ARC code only" the naming conventions are "less important", but this is not 100% true. Apple指南说,“仅ARC代码”的命名约定“不太重要”,但这并不是100%正确的。

For example (and this is only one example, I think that there are many other), look at this project 例如(这只是一个例子,我想还有很多其他例子),请看一下这个项目

I swizzled release-autorelease calls to log it, and you can see the difference: 我将release-autorelease调用都记录下来,您可以看到其中的区别:

when a method begins with a special naming (for example "new"), ARC returns an object with a retain count of +1, that is balanced by release calls. 当方法以特殊命名(例如“ new”)开头时,ARC返回一个保留计数为+1的对象,该对象由释放调用平衡。
When a difference name is used, ARC returns an AUTORELEASED object. 使用差异名称时,ARC返回一个AUTORELEASED对象。 (look at the NSLog calls) (查看NSLog调用)

This can be a big difference in code that alloc a great number of objects in a loop. 在循环中分配大量对象的代码中,这可能是一个很大的差异。 In this case, the programmer should create an autorelease pool. 在这种情况下,程序员应创建一个自动释放池。

So, it's not true that the naming conventions are less important when using ARC-only code. 因此,使用仅ARC的代码时,命名约定的重要性并不那么重要。

I don't know all of the details on naming methods 100% conventionally because there are different situations that apply to each. 按照惯例,我不了解有关命名方法的所有详细信息,而是100%,因为每种情况都有不同的情况。 however I think this article in the Apple docs will help you. 但是我认为Apple文档中的这篇文章会为您提供帮助。 https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Conventions/Conventions.html https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Conventions/Conventions.html

First, memory management has nothing to do with the names you choose for your methods or classes. 首先,内存管理与为方法或类选择的名称无关。 In other words if it compiles and you're not using reserved keywords or critical method names you should be good. 换句话说,如果它可以编译并且您没有使用保留关键字或关键方法名称,那么您应该很好。 (Please refer to Edit note) (请参阅编辑注释)

As for 1, preceding new is very uncommon in Objective-C, so it's better to use objectFrom: instead. 至于1,之前的new在Objective-C中很少见,因此最好使用objectFrom:

Even better would be to be more precise about the kind of object you're creating. 更好的是要更精确地创建您要创建的对象的类型。 For example: 例如:

[NSArray arrayWithArray:]
[NSString stringWithFormat:]

Or in your case as you create a copy, and supposing you're creating "Client" objects: 或者在您创建副本的情况下,并假设您正在创建“客户端”对象:

[Client clientWithClient:options:]

Where with is not really needed. with是不是真的需要。

For 2 I would choose: 对于2我将选择:

copyWithOptions:

As you're more or less customizing [NSObject copy] . 随着您或多或少地定制[NSObject copy] I would also implement only this method and delete the now redundant 1 as less methods is clearer, easier to document, and easier to maintain! 我也将仅实现此方法并删除现在多余的1,因为更少的方法更清晰,易于记录且易于维护!

In case of doubt just search the SDK documentation to see how similar methods were named by Apple. 如有疑问,请搜索SDK文档,以了解Apple如何命名类似的方法。

Edit: 编辑:

In the first paragraph I don't mean to encourage bad naming practices, just to say that they are not the reason for your memory management concerns. 在第一段中,我并不是要鼓励不良的命名习惯,只是说它们不是引起您的内存管理问题的原因。 Yet you should try to follow the naming conventions pointed in the other answers, or as I said, "do as Apple does". 但是,您应该尝试遵循其他答案中指出的命名约定,或者正如我所说的,“像Apple一样”。

My experience in the apple world is that factory methods like your examples would usually include 'create' by convention. 我在苹果世界中的经验是,像您的示例这样的工厂方法通常会按惯例包括“创建”。 This is probably less important now with ARC but in the old days 'create' in a method or function signature was a pretty sure fire way to be sure you understood you were taking ownership of the resulting object (owing a release/free() on it) rather than an instance type which you would assume to autorelease [NSArray array] , [UIColor colorWith....] etc, so I still definitely like to follow this convention. 现在,这对于ARC来说可能不再那么重要了,但是在过去,方法或函数签名中的“创建”是一种非常确定的方法,可以确保您了解自己对结果对象的所有权(由于release / free()它),而不是您假设会自动释放[NSArray array],[UIColor colorWith ....]等的实例类型,因此我仍然绝对希望遵循此约定。

  1. ARC gave semantics to what used to be a naming convention for tracking reference counting responsibilities. ARC为以前用来跟踪引用计数职责的命名约定提供了语义。 So now the compiler uses the same naming patterns to determine whether a method returns a retained object, etc. See the link in @JodyHagens' answer and continue reading with http://clang.llvm.org/docs/AutomaticReferenceCounting.html#semantics-of-method-families 因此,现在编译器使用相同的命名模式来确定方法是否返回保留的对象,等等。请参见@JodyHagens答案中的链接,并继续阅读http://clang.llvm.org/docs/AutomaticReferenceCounting.html#semantics方法家庭

    Methods in the alloc , copy , mutableCopy , and new families — that is, methods in all the currently-defined families except init — implicitly return a retained object as if they were annotated with the ns_returns_retained attribute. alloccopymutableCopynew系列中的方法(即,除init以外的所有当前定义的系列中的方法)隐式返回保留的对象,就像它们使用ns_returns_retained属性进行了注释ns_returns_retained This can be overridden by annotating the method with either of the ns_returns_autoreleased or ns_returns_not_retained attributes. 可以通过使用ns_returns_autoreleasedns_returns_not_retained属性之一对方法进行注释来覆盖此方法。

    The " new family" is the message selectors that start with "new" followed by an upper case letter. new家族”是消息选择器,以“ new”开头,后跟一个大写字母。 So there are memory management differences between newObjectFrom:withOptions: and objectFrom:withOptions: , but you can use an annotation to override that (don't go there), and the compiler should complain if you get it wrong. 因此, 之间的内存管理差异newObjectFrom:withOptions:objectFrom:withOptions: ,但你可以使用注释来重写(不要去那里),如果你弄错了编译器应该抱怨。

    (All methods that implement a given message selector had better provide the same reference counting semantics.) (实现给定消息选择器的所有方法最好都提供相同的引用计数语义。)

  2. In addition to Apple's article on Conventions that @iRebel_85 points out, Apple has an extensive set of naming guidelines . 除了苹果公司 @ iRebel_85指出的有关约定的文章外, 苹果公司还提供了广泛的命名准则

  3. Google's style guide adds a few more naming guidelines . Google的样式指南增加了一些命名指南

These guidelines are well thought out and useful for making code easier to understand and collaborate on. 这些准则经过深思熟虑,对于使代码更易于理解和协作非常有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM