12.iOS中的ARC内存管理机制
1. @property 声明属性
1.1 本质
使用@property声明属性,编译器可以自动合成实例变量(_属性名)、getter方法和setter方法
1.2 在 @protocol 和 category 中使用 @property
在protocol中使用property只会生成setter方法和getter方法声明,使用属性的目的是希望遵守协议的对象能实现该属性。
category使用
@property
,编译器不会自动合成setter方法和getter方法,类别中无法把实现属性所需的实例变量及其存取方法合成出来,而需要在实现文件中使用@dynamic + 属性名;
的方法告诉编译器在运行时添加setter方法和getter方法,或者是直接在类的实现文件中直接添加该属性的setter方法和getter方法。
1.3 修饰符
1.3.1 原子性
atomic(默认属性):线程保护技术,防止在未写完成的时候被另外一个线程读取,造成数据错误,这种机制耗费系统资源的。
noatomic:访问器只是简单返回这个值,访问速度快。
1.3.3 读写权限
readwrite(读写):同时生成读写方法
readonly(只读):只生成getter方法
1.3.4 内存管理
这些内存管理的属性只影响设置方法——setter方法
assign:设置方法只会针对基本的数据类型进行简单的赋值操作
strong:strong类型的属性定义了一种“拥有的关系”,当这种属性设置新值时,会先保留新值,再释放旧值,然后将新值设置给该属性
weak:定义了属性间的非拥有的关系,与强引用不同的是weak弱引用既不保留新值,也不释放旧值,与assign类似,当该属性指向的对象被销毁时,属性值被自动设为nil。
runtime 如何实现 weak 变量的自动置nil?
runtime对注册的类,会进行布局,对于weak属性的对象会存入一个hash表中,用weak指向的对象的内存地址作为key,当此对象的引用计数为0的时候会调用dealloc方法,,此时hash表中找到以key为键所对应的那个对象设置为nil。
unsafe_unretained:与weak属性类似,不同的是unsafe_unretained属性在进行是方法的时候,并不会将该属性置为nil,而是直接释放,这样就会出现野指针,再向这个属性发送消息时会造成程序因异常而结束。
copy:与strong属性类似,但是weak属性并不保留新值,而是拷贝新值的一个副本,并赋给该属性,这样保护了程序的封装性。
方法名:可以在定义属性的时候设置该属性的存取方法名。
2. ARC的本质
ARC是编译时的特性,而不是运行时特性,也不是垃圾回收机制。ARC是自动引用计数,是对MRC的改进。
2.1 ARC下的变量修饰符:
-
__strong
:(默认)对应property中的strong修饰符,所有对象只有当没有任何一个强引用指向是,才会被释放。如果需要释放强引用指向的对象时,需要将强引用置为nil。 -
__weak
:对应property中的weak修饰符,弱引用不会持有对象,只要对象没有强引用指向,就会在该程序段结束后释放,同时将该变量指向的内存置为空。 -
__autoreleasing
:会将使用__autoreleasing修饰的属性放入自动释放池。 -
__unsafe_unretained
:与weak的作用类似,没有任何额外的操作,但是在指向对象被释放时依然原原本本地指向原来被释放的对象(所在的内存区域)。所以非常不安全。
2.2 ARC与block
-
在MRC中,block会对进入其作用域内的对象(或被block捕获的指针指向的对象)隐式的添加retain,来保证block可以正确使用该对象。但此时容易出现循环引用的问题,即block引用了该类的实例变量,而该类的实例变量用持有该block,这就需要在block使用该对象之前,用__block修饰符修饰该对象。
在MRC中使用
__block
的作用:- 说明变量可改。(静态变量和全局变量,实例变量在block中是可以被改变的)
- 说明指针指向的对象不能做隐式的retain操作。
-
在ARC中,没有了retain和release操作,此时使用
__ block
只影响了变量的可修改属性,被block捕获的强引用还是强引用,依旧会造成循环引用的状况。此时需要使用__weak
生成一个弱引用,指向需要在block中使用的强引用:ViewController * __weak weakSelf = self; //或者 __weak typeof(self) weakSelf = self;
4. ARC与Toll-Free Bridging
Toll-Free Bridging是使用户可以方便的使用同一种语法来使用CoreFoundation对象和Objective-C对象。
MRC时,OC对象和CF对象多使用相同的release和retain操作
ARC时,OC对象的内存管理规则改变,而CF对象依然是之前的机制(不支持ARC机制)
-
引入ARC后对Toll-Free Bridging的操作加入对应的方法与修饰符,用来指明用哪种规则管理内存,或者说是内存管理权的归属。
-
__bridge
(修饰符):只是声明类型转变,但是不做内存管理规则的转变。 -
__bridge_retained
(修饰符) 或CFBridgingRetain
(函数):表示将指针类型转变的同时,将内存管理的责任由原来的Objective-C交给Core Foundation来处理,也就是,将ARC转变为MRC。 -
__bridge_transfer
(修饰符) 或CFBridgingRelease
(函数):功能和上面的__bridge_retained相反,它表示将管理的责任由Core Foundation转交给Objective-C,即将管理方式由MRC转变为ARC。
-
3. MRC手动释放引用计数
一个new/alloc/retain/copy/muticopy对应一个release和一个autorelease。