# 30、以ARC简化引用计数

​ Clang编译器项目带有一个“静态分析器”（static analyzer），用于指明程序里引用计数出问题的地方。

​ 方法命名规范：

1. `alloc`、new、`copy`、mutableCopy开头的方法内部会调用retain，使引用计数+1，方便调用者持有返回的对象，调用者也需要负责释放该对象。
2. 其他开头的方法内部会调用`autorelease`，使对象在跨越方法调用边界后依然有效，但过段时间会被释放。要想令调用者持有它，需要执行保留方法才行。

维系这些规则所需的全部内存管理事宜均由ARC自动处理，如：

```objectivec
// 以new开头，调用者需要持有对象；所以其引用计数需要+1
+ (Person *)newPerson {
    Person *person = [[Person alloc] init]; // alloc开头：引用计数已经+1
  return person;
} // 所以ARC什么代码都不需要加

// 不是以“owning prefixs”开头，调用者不需要持有对象；所以其引用计数不需要+1
+ (Person *)somePerson {
    Person *person = [[Person alloc] init]; // alloc开头：引用计数已经+1
  return person;
  // 所以ARC会在改为类似 return [person autorelease]; 的代码
} 

+ (Person *)doSomething {
    Person *personOne = [Person newPerson];
  Person *personTwo = [Person somePerson]; // autorelease
  // 所以ARC会添加类似  [personOne release]; 的代码
}
```

​ ARC会把能互相抵消的`retain`、release、`autorelease`操作约简。如在发现同一个对象上执行了多次“保留”与“释放”操作，则可以成对移除这两操作。如：

```objectivec
Person *tmp = [Person personWithName:@"momo"];
_myPerson = [tmp retain];
// personWithName: 里的autorelease和后面的retain都是多余的。
// 为了提升性能皆可省去
```

​ 为了优化代码，在方法中返回自动释放的对象时，调用的是`objc_autoreleaseReturnValue`，此函数会检视当前方法返回之后即将要执行的那段代码，若发现那段代码要在返回的对象上执行`retain`操作，则会根据当前对象在全局数据结构中设置一个标志位，并不执行`autorelease`操作。相似的保留对象调用的是`objc_retainAutoreleaseReturnValue`函数，此函数会根据当前对象到全局数据结构中找到刚才那个标志位，若已置位，则不执行`retain`操作。（设置并检测标志位，要比调用`autorelease`和`retain`更快）例如：

```objectivec
// objc_xxx：直接调用C函数，不经过OC的消息派发，速度更快
+ (Person *)personWithName:(NSSrting *)name {
  Person *person = [[Person alloc] init];
  person.name = name;
  objc_autoreleaseReturnValue(person); //
}
Person *tmp = [Person personWithName:@"Momo"];
_myPerson = objc_retainAutoreleaseReturnValue(tmp); //
```

要点：

* 有ARC后，程序员无须担心内存管理问题，可省去类中的许多“样板代码”
* ARC管理对象生命期的办法基本上就是：在合适的地方插入“保留”及“释放”操作。在ARC环境下，变量的内存管理语义可以通过修饰符指明，而原来则需要手工执行“保留”及“释放”操作
* 由方法返回的对象，其内存管理语义是通过方法名来体现。ARC将此确定为开发者必须遵守的规则
* ARC只负责管理OC对象的内存。尤其要注意：`CoreFoundation`对象不归ARC管理，开发者必须适时调用`CFRetain`/CFRelease。
