1.概念
ARC即自动引用计数,系统帮我们处理引用计数。
clang (LLVM编译器) 3.0或以上版本。
指定编译器属性为 -fobjc-arc
2.规则
- 不能使用retain,release,autorelease等方法。
- 不要显示的调用dealloc。
- 使用@autoreleasepool块代替NSAAutorelease。
3.所有权修饰符
ARC下,我们不能使用retain,release等方法管理内存。我们使用所有权修饰符,系统根据所有权修饰符帮我们管理内存。有以下4种:
- __strong
- __weak
- __unsafe_unretained
- __autoreleasing
-
__strong表示强引用,持有对象实例,使对象的引用计数加一。__strong为默认修饰符,一般我们省略写__strong。
-
为了解决强引用循环引用的问题使用__weak弱引用。 弱引用不能持有对象,不能使引用计数加一。 如果对象被释放后,访问弱引用则返回nil。
-
__unsafe_unretained也和__weak一样不持有对象。如果对象被释放后,访问__unsafe_unretained对象,会访问野指针,造成崩溃。
-
__autoreleasing 在arc下不能使用autorelease方法,使用__autoreleasing修饰符来将对象加入pool中。
4.属性
属性和修饰符的对应关系:
assign 对应 __unsafe_unretained修饰符
copy 对应 __strong修饰符 (但是赋值的是被赋值的对象)
retain 对应 __strong修饰符
strong 对应 __strong修饰符
weak 对应 __weak修饰符
unsafe_unretained 对应 __unsafe_unretained修饰符
5.__strong的实现
1.对于使用alloc方法等:
{ id __strong obj = [[NSObject alloc] init];
}
编译器的模拟代码
id obj = objc_msgSend(NSObject,@selector(alloc));
objc_msgSend(obj,@selector(init));
objc_release(obj);
2.对于类方法:
{ id __strong obj = [NSMutableArray array];
}
编译器模拟代码
id obj = objc_msgSend(NSMutableArray,@selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);
+(id) array { return [[NSMutableArray alloc] init];
}
编译器模拟代码
id obj = objc_msgSend(NSMutableArray,@selector(alloc));
objc_msgSend(obj,@selector(init));
return objc_autoreleaseReturnValue(obj);
本来类方法生成的对象应该注册autoreleasepool中,但是做了优化,使用Objc_autoreleaseReturnValue 和 objc_retainAutoreleasedReturnValue 直接将对象传递到函数的调用方。
3.对于持有不是自己生成的对象
{
id __strong obj = [[NSObject alloc] init];
id obj2 = obj;
}
编译器实现代码
id obj = objc_msgSend(NSObject,@selector(alloc));
objc_msgSend(obj,@selector(init));
id obj2 = objc_retain(obj);
objc_release(obj);
objc_release(obj2);
5.__weak的实现
- __weak 使用散列表来实现,若附有__weak的变量所引用的对象被废弃, 则将nil赋值给该变量。
id __weak obj2 = obj; 编译模拟代码如下:
objc_initWeak(&obj, obj2);
init函数会调用objc_storeWeak(&obj,obj2);
- 将对象的地址作为键值,将弱引用变量的地址注册到weak表中。 一个变量的地址键值可以对应多个弱引用变量。
- 当弱引用变量不指向对象时,将弱引用变量的地址从weak表中移除。
- 当对象被销毁,会将记录中的所有弱引用变量赋值为nil。
2.使用附有__weak的变量,即是使用注册到autoreleasepool中的对象。
__weak修饰符只持有对象的弱引用,而在访问引用对象的过程中,该对象可能被废弃,而如果把要访问的对象注册到autoreleasepool中,在@autoreleasepool块结束之前都能确保该对象存在。
{ id __weak obj1 = obj;
}
源码转换如下形式:
id obj1;
objc_initWeak(&obj1,obj);
id tmp = objc_loadWeakRetained(&obj1);
objc_autorelease(tmp);
objc_loadWeakRetained 函数取出__weak所引用的对象并retain。
网友评论