在《Objective-C高级编程:iOS与OS X多线程和内存管理》一书中,对于ARC的部分有详尽的讲解。我将这一部分整理成思维导图,算是一个归档吧。
如下是一些需要注意的点:
0.id
id
是OC中对象标识的数据类型,可以用来指定任何类。id
是所有对象的终极超类。<objc/objc.h>
中id
的定义:
|
|
- 虽然看起来是指向结构体的指针,但对于OC的编译器而言,
id
使得原本的静态类型的语言变得动态起来。这就意味着,它指向的对象的类型是不被编译器检查的。 - ARC有效时,
id
类型和对象类型同C语言其他类型不同,其类型上必须附加所有权修饰符,包括:__strong
,__weak
,__unsafe_unretain
和__autoreleasing
修饰符。 __strong
,__weak
和__autoreleasing
修饰符一起,可以保证将附有这些修饰符的自动变量初始化为nil
。
1.引用计数规则
- 谁使用谁释放,谁创建谁释放。(谁污染谁治理 =。=)
2.是在预编译/编译/链接/运行 哪个阶段进行?
- 所有的retain、release、strong属性的会在编译时处理。
- weak属性会在运行时处理。
3.__strong
、__weak
、__unsafe_unretain
__strong
:是id
类型和对象类型默认的所有权修饰符。附有__strong
修饰符的变量,在超出其变量作用域时,即在该变量被废弃时,会释放其被赋予的对象。表示逻辑上强持有一个对象。规则是:指针被赋值时同时进行retain处理;指针销毁时对指针的内容进行release。__weak
:指针被赋值时,不会对所赋的对象进行retain,意味着引用计数会随时为零,一旦为零,就会被置为nil
,也就是说,要再引用计数为零之前置为nil
。__unsafe_unretain
:不安全的不持有。规则是:声明一个指针,对赋值的对象不进行retain,如果对象为零了,那么指针会继续指向这个对象。__weak
会有性能损耗,所以在处理极大对象的时候会使用__unsafe_unretain
属性。
4.strong
,weak
,assign
strong
:和__strong
是一样的,在dealloc的时候release。weak
:和__weak
是一样的,一旦引用计数变为零,会自动置为nil
。assign
:能够声明很多标量(float,int等),用它来声明变量时,和__unsafe_unretain
一样,声明一个指针的时候会对它进行持有,当为零的时候也不会自动释放。
5.weak
详解
- 工作在运行时:编译时是按照逻辑编译单元(一个.m文件)进行编译的,在一个编译单元中无法知道其他编译单元的情况,无法判断是否为零、是否需要置为
nil
。 - 如何置为
nil
:底层有一个哈希表,哈希表中存储所有weak指向的对象。用weak指针指向的值(对象的地址,是一个栈/堆上的变量)作为key,所有指向它的地址作为value。每当对象dealloc时,就会检查这个表,同时把表中所有指向这个对象的指针都置为nil。
6.归零弱引用(Zeroing weak reference)
即让对象自己去清空弱引用的对象,这种特殊的弱引用被称为归零弱引用。在它指向的对象释放后,这些弱引用会被设置为零(即nil)。
有两种方式可以声明归零弱引用:
- 声明变量时使用
__weak
关键字或对属性使用weak特性。 - 在不支持弱引用的旧系统上,可以使用苹果公司提供的
__unsafe_unretained
关键字和unsafe_unretained
特性。
7.循环引用
a.propertyB = b; b.propertyA = a;
b的引用计数+1,a的引用计数+1。引用计数一直无法为零,造成循环引用。- 如何解?
- 原因在于,b和a都会引用计数至少为1。
- 暴力解法:b或者a多调用一下release。然后就挂了。ㄟ( ▔. ▔ )ㄏ
- 简单解法:任何一端置为nil。
Ref
- 《Objective-C高级编程:iOS与OS X多线程和内存管理》
- 臧成威《现代OC内存管理》:http://www.stuq.org/course/1044/courseware/1594