四、自动释放池 (autorelease)
1)基本原理:
1> 自动释放池是OC里面一种内存管理的自动回收机制,一般可以将临时变量添加到自动释放池中,统一回收释放。
2> 当自动释放池销毁的时候,在自动释放池中所有的对象都会调用一次release方法。
3> OC对象只要发送一条autorelease消息,会把对象方法放在最近的释放池中(栈顶的释放池)。
4> autorelease实际上是延迟了release方法的调用,每一次autorelease就会把对象放在当前的autorelease pool中,当pool被释放时,在pool中所有的对象调用该一次release。
2)自动释放池的创建:
1> ios 5.0后:
@autoreleasepool{
//..........
}
2> ios 5.0之前:
NSAutoreleasePool *pool=
[[NSAutoreleasePool alloc]init];
//...............
[pool release] ;或者 [pool drain];
3)autorelease的使用:
1> 以前:
Book *book = [[BooK alloc] init];
[Student setBooK:book];
[book release];
2> 现在:
Book *book =[[[Book alloc] init] autorelease];
[Student setBook:book];
//不在调用[book release];
3> 快速创建对象的静态方法:
+ (id) person{
return [[[Person alloc] init]autorelease];
}
外部调用[Person person]时,根本不用考虑什么时候释放返回Person对象。
4)autoreleasepool的相关疑问:
疑问:
在iPhone项目中,main()中有一个默认的Autorelease Pool,程序开始时创建,程序退出时销毁,按照对Autorelease的理解,岂不是Autorelease Pool里的所有对象在程序退出时才release,这样跟内存泄露有什么区别?
解答:
对于每一个Runloop, 系统会隐式创建一个Autorelease pool,并且把创建好的pool放在栈顶,所有的pool会构成一个栈式结构。在每一个Runloop结束时,当前栈顶的pool会被销毁,这样这个pool里的每个对象会执行release操作。
5)autoreleasepool的使用注意:
1> 在ARC模式下不能使用[[AutoreleasePool alloc] init] ,而应当使用@autoreleasepool。
2> 不要把大量的循环操作放在NSAutoreleasePool之间,这样会造成内存的峰值上升。
3> 对于大内存尽量避免使用这种方法,对于这种延迟释放机制还是少用。
4> sdk中一般利用静态方法创建并返回的对象一本都已经autorelease的,不在需要release了。
6)@property的参数
1> 参数可有可无:
@property int age;
@property(nonatomic,retain) NSString * name;
2> 参数的分类:
读写属性:readwrite/readonly;
setter处理:assign/retain/copy;
原子性:atomic/nonatomic;
3> 默认参数是atomic
提供多线程保护,在多线程保护下,原子操作是有必要的,否则可能引起错误的结果。
加了atomic,setter/getter是一个原子操作,如果有多个线程同时调用setter的话,不会出现某个线程在执行setter的全部语句之前,另一个线程开始执行setter的情况,相当于函数头尾加了锁一样的。
4> 常用的参数noatomic
写上之后是说明禁止多线程,保护变量,提高性能。
atomic是OC使用的一种多线程保护机制,防止写入没有完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iphone这种小型设备上,如果没有使用多线程的通讯编程,那nonatomic是一个非常好的选择。另外不涉及锁操作,所以它执行相对快点。
5> @property其他参数
readwrite: 产生setter\getter readonly: 只产生简单的getter,没有setter。
assign: 默认类型,setter方法直接赋值,而不进行retain操作
retain: setter方法release旧值,再retain新值
copy: setter方法release旧值,再copy新值