命名方法的简单规则,与ARC命名约定兼容 [英] Simple rules for naming methods, compatible with ARC naming conventions

查看:57
本文介绍了命名方法的简单规则,与ARC命名约定兼容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难理解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规则; p>

  • (和/或)在没有ARC的情况下不涉及内存管理的规则;

  • (和/或)不使用诸如"autorelease","release"之类的词的规则.

解决方案

里维拉说方法名称并不重要时,他可能会遵循他的经验:它总是有效的.这是正确的.而且您是正确的,因为您一直使用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 :有时您需要一个自动释放池. 为了使ARP的优势可见,请考虑以下代码:(这只是为了演示问题,没用

案例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两种方法的实现都是相同的.

-> 您不再需要任何此规则. ARC会照顾您四个.

尤其是,您不再需要便利分配器,因为不再有任何不便之处. (即使它们在运行时进行了优化,运行时的损失也仍然很小.)我不再实现便利性分配器,而是新的分配器.

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

I have difficulties understanding naming conventions of ARC. I have always coded with ARC, and I guess this is the reason.

1. Class methods

  • 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

  • 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

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";

  • (and/or) a rule that does not refer to the memory management without ARC;

  • (and/or) a rule that does not use words such as "autorelease", "release".

解决方案

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. So what is the big deal with it?

I added a synopsis to show the problem with MRR at the end of this answer. As you can see there, you do not have to care about naming rules using ARC the way you had to with MRR.

To give you a more detailed explanation, you have to understand what happens using MRR:

Prior to ARC one had to do memory management manually. 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. 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. 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. Or in one word: Ownership transfer:

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

As -retain took the ownership explicitly, alloc–, init…, new… transferred it implicitly.

All other methods behaves like rule 1.

Rule 3: Sometime you need an autorelease pool. To make the advantage of ARPs visible think of this code: (It is useless, just to demonstrate the problem

Case 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:

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. So it lives through every method, through method return and so on. To do it explicitly:

Case 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:

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:

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.

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.)

Rule 3: Use -autorelease to delay the deallocation of returned objects for convenience.

Synopsis:

Alloc-init creation

// 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. 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.

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.

-> You do not need it any of this rules any more. ARC cares four you.

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. 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命名约定兼容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆