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属性。

浙公网安备 33010602011771号