ARC规则

ARC规则

ARC标记

编译器属性设置为"-fobj-arc",则此文件采用arc编译,默认才是此编译方式.
如果是采用MRC编译,则必须加上标识-fno-objc-arc

ARC所有权修饰符

  • __strong
  • __weak
  • __unsafe_unretained
  • __autoreleasing

__strong

是默认所有的id类型和对象类型的所有权修饰符。
比如id obj = [[NSObject alloc] init];等同于id __strong obj = [[NSObject alloc] init];

id类型用于隐藏对象的类型,相当于C语言中常用的"void *"。

__weak

为了解决内存管理中"循环引用"的问题,而引入的修饰符。代有__weak修饰符的变量,表示自己不持有变量,在超出其变量作用域的时候,变量及被释放。同时当持有的对象被废弃时,则此变量引用会自动失效并且处于nil状态。

下面的例子就会出现相互强引用现象,导致内存泄露。

id test0 = [[Test alloc] init];
id test1 = [[Test alloc] init];
[test0 setObject:test1];
[test1 setObject:test0];

解决方法,就是定义变量的时候,使用__weak修饰符

@interface Test:NSObject
{
id _weak obj;
}

  • (void)setObject:(id __strong)obj;
    @end

下面的例子就会出现*自身强引用*的现象。

id test = [[Test alloc] init];
[test setObject:test];

> 在iOS4中,```__weak```使用```__unsafe_unretained```来代替。

### __unsafe_unretained
>```__unsafe_unretained```关键字等同于assign,功能和```__weak```几乎一样。不同点就是```__weak```关键字指向的对象销毁掉以后,此变量会自动设置为nil,防止野指针调用。而用```__unsafe_unretained```关键字指向的对象销毁掉以后,次变量不会设置为nil,会导致野指针调用。

##ARC规则
在ARC有效的情况下,必须遵守一定的规则。
* 不能使用*retain*/*release*/*retainCount*/*autorelease*
* 不能使用*NSAllocateObject*/*NSDeallocateObject*
* 必须遵守内存管理的命名规则
* 不能显式调用*dealloc*
* 使用*@autoreleasepool*代替*NSAutoreleasePool*
* 不能使用区域(*NSZone*)
* 对象型变量不能作为C语言结构体(struct/union)的成员
* 显示转换"id"和"void *"

### 方法命名
>使用一下名称开头的方法在返回对象时,必须返回给调用方所持有的对象。
> * alloc
> * new
> * copy
> * mutableCopy

### init
>以init开头的方法命名更严格,必须是实例方法,并且必须返回对象。除了```- (void)initialize;```方法外。

### dealloc
>不必书写```[super dealloc];```,现在delloc方法中一般只是使用删除代理、观察者对象、KVO对象。

### 显式转换id和void *
>不能直接把id赋值给void *指针,两者转换或者赋值必须使用```__bridge```来进行转换

id obj = [[NSObject alloc] init];
void *p = (__bridge void *)obj;
id 0 = (__bridge id)p;

>```__bridge```的安全性和赋值和```__unsafe_unretained```接近,甚至安全性更低,如果管理时不注意赋值对象的所有者,就会因为垂直指针而导致程序崩溃。
```__bridge```分为两种转换,分别是```__bridge_retained```和```__bridge_transfer```,作用分别相当于retain和release。

### Object-C对象和Core Fundation对象转换

* Core Fundation框架中的retain/release分别是*CFRetain*和*CFRelease*。
* 不能直接使用```__bridge```来转换Object-C对象和Core Fundation对象,```__bridge```不会增加计数器,所以导致```CFRelease```方法时,因为没有计数为0,所以导致出错。
* 当Object-C对象转为Core Fundation对象,应使用*CFBridgingRetain*方法或者*__bridge_retained CFTypeRef*来转换。这两个方法会使对象计数器加1。
> ```
> id obj = [[NSMutableArray alloc] init];
> CFMutableArrayRef cfObject = (__bridge_retained CFMutableArrayRef)obj;
>```
>或者是:
> ```
> id obj = [[NSMutableArray alloc] init];
> CFMutableArrayRef cfObject = CFBridgingRetain(obj);
>```
* 当Core Fundation对象转为Object-C对象,应使用*CFBridgingRelease*方法或者*__bridge_tranfer id*来转换。这两个方法会使对象计数器减1。
> ```
> CFMutableArrayRef cfObject = CFMutableArrayRef(kCFAllocatorDefault, 0, NULL);
> id obj = (__bridge_tranfer id)cfObject;
>```
>或者是:
> ```
> CFMutableArrayRef cfObject = CFMutableArrayRef(kCFAllocatorDefault, 0, NULL);
> id obj = CFBridgingRelease(cfObject);
>```


## ARC属性声明(@property)

###内存管理属性
| 属性声明的属性 | 所有权修饰符 |
| ------------ |: -------- :|
| *assign*       | __unsafe_unretained修饰符 |
| *copy*         | __strong修饰符(但是赋值的是被复制的对象)|
| *retain*         | __strong修饰符 |
| *strong*         | __strong修饰符 |
| *__unsafe_unretained*       | __unsafe_unretained修饰符 |
| *weak*         | __weak修饰符 |

> copy属性,它的赋值是通过*NSCopying*借口的*copuWithZone:*方法复制赋值所给的对象。
> 在声明类成员时,如果同属性声明中的属性不一致也会引起编译器出错。

* assign
> assign表示直接赋值,用于基本数据类型(NSInteger和CGFloat)和C数据类型(如int, float, double, char等)另外还有id类型,这个修饰符不会牵涉到内存管理。但是如果是对象类型,使用此修饰符则可能会导致内存泄漏或EXC_BAD_ACCESS错误;

* copy
> copy表示复制对象,主要用于NSString类型或者UIColor继承*NSCopying*借口的*copuWithZone:*方法的对象。可以使用strong来代替。

* retain
> retain针对对象类型进行内存管理。在setter方法中会先release掉旧的赋值,然后对新的赋值retain一次。可以使用strong来代替。

* strong
> strong主要针对对象类型,不能用于基础类型。strong的作用和retain作用相同,但是对于NSString类型等一些对象会使用copy复制对象赋值。在ARC中建议尽量使用strong来代替retain和copy。

* weak
> weak来表示弱引用类型对象或者基础数据类型。功能和assign接近,但是在属性释放后会自动将属性赋值nil。所以弱类型的引用对象属性应该用weak,而不是assign,比如delegate。

###线程安全属性
* nonatomic
> 表示属性是非线程安全的,但是使用此属性性能会提高一些。

* atomic
> 表示属性是线程安全的。

###可读性属性
* readonly
> 表明变量只有可读方法,也就是说,你只能使用它的get方法。

* readwrite
> 默认属性,通过加入readwrite属性你的变量就会有get方法,和set方法。如果使用系统自带的setter和getter方法,则通过*@synthesize*关键词来自动定义。

###setter和getter方法
* setter
> 指定属性的setter方法,使用方式```@property (retain,nonatomic,setter = setMyNewArray:) NSArray *arrayTest;```

* getter
> 指定属性的setter方法,用法同setter。

###可空性属性(Xcode 6.3新增)
* nullable
> 类型注释为:__nullable,表示对象可以是NULL或nil。

* nonnull
> 类型注释为:__nonnull,表示对象不可以是NULL或nil。如果违反这些规则,编译器会发出警告。

> 当类型定义中大部分都是非空类型的时候,可以使用*NS_ASSUME_NONNULL_BEGIN*和*NS_ASSUME_NONNULL_END*来包括所有的@property属性定义,而需要定义可以为空属性的属性,可以单独添加nullable属性。
posted @ 2015-08-11 13:18  前尘如梦  阅读(314)  评论(0)    收藏  举报