内存管理做为iOS中很是重要的部分,每个iOS开发者都应该深刻了解iOS内存管理,最近在学习iOS中整理出了一些知识点,先从MRC开始提及。数组
1.当一个对象在建立以后它的引用计数器为1,当调用这个对象的alloc、retain、new、copy方法以后引用计数器自动在原来的基础上加1(ObjC中调用一个对象的方法就是给这个对象发送一个消息),当调用这个对象的release方法以后它的引用计数器减1,若是一个对象的引用计数器为0,则系统会自动调用这个对象的dealloc方法来销毁这个对象。安全
2.@property的参数能够分为三类,也就是说最多能够有三个参数,参数的含义以下表:框架
参数类型学习 |
参数名atom |
参数含义spa |
原子性线程 |
atomiccode |
对属性加锁,线程安全,默认属性orm |
nonatomic对象 |
不加锁,非线程安全 |
|
读写属性 |
readonly |
生成getter和setter方法,默认属性 |
readwrite |
只生成getter方法 |
|
set方法处理 |
assign |
直接赋值,默认值 |
retain |
先release原来的值,再retain新值 |
|
copy |
先release原来的值,再copy新值 |
各类属性对应的setter方法内容以下:
assign, 一般用于基本数据类型,如:int,float
-(void)setA:(int)a{ _a=a; }
retain,一般用于非字符串对象
-(void)setA:(A *)a{ if(_a!=a){ [_a release]; _a=[a retain]; } }
copy,一般用于字符串对象,block,NSArray,NSDictionary
-(void)setA:(NSString *)a{ if(_a!=a){ [_a release]; _a=[a copy]; } }
3. 当使用手动引用计数的时候,Fundation框架中的一些方法可能会增长对象的引用计数,好比NSMutableArray中的addObject或者UIView中的addSubview,有一些方法将会减小对象的引用计数好比上面两个接口对应的removeObjectAtIndex和removeFromSuperview。
4.再建立对象的时候推荐使用[[className alloc]init]而不是[className new],由于若是使用[className new],内部是调用的init方法初始化,咱们就无法调用initWithFrame之类的方法。
5.alloc:对象分配后引用计数为1,retain:对象的引用计数+1,copy:开辟新的内存存放新对象,引用计数为1,原对象引用计数不变。
6.给对象发送release消息并不必定会销毁这个对象,而是将对象的引用计数-1,若是对象的引用计数为0的话,对象就会被销毁。而后系统会发送dealloc消息给这个对象释放它的内存。
7.对使用了retain、copy、mutableCopy、alloc、new方法的任何对象,以及具备retain和copy特性的属性进行释放,须要覆盖dealloc方法,使得在对象被释放的时候可以释放这些实例变量。
8.NSAutoreleasePool内部包含一个数组(NSMutableArray),用来保存声明为autorelease的全部对象。若是一个对象声明为autorelease,系统所作的工做就是把这个对象加入到这个数组中去。
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1,把此对象加入autorelease pool中
NSAutoreleasePool自身在销毁的时候,会遍历一遍这个数组,release数组中的每一个成员。若是此时数组中成员的retain count为1,那么release以后,retain count为0,对象正式被销毁。若是此时数组中成员的retain count大于1,那么release以后,retain count大于0,此对象依然没有被销毁,内存泄露。若是再方法中不须要再使用这个对象,可是须要将其返回,能够向这个对象发送autorelease消息将其放入到自动释放池用以标记这个对象延迟释放,autorelease并不会影响到对象的引用计数。
ClassA *Func1() { ClassA *obj = [[[ClassA alloc]init]autorelease]; return obj; }
当引用程序终止的时候,内存中全部的对象都会被释放,不管是否放入到自动释放池中。若是对对象比较大的话不建议放入到自动释放池中,由于自动释放池延迟释放会致使程序占用内存较多。在iOS程序中会建立许多的自动释放池,这些自动释放池都是以栈(先进后出)的形式进行管理的,好比有两个嵌套的自动释放池:
@autoreleasepool { // 对象的释放交给 自动释放池去管理 不用再写[person release] Person *person = [[[Person alloc] init] autorelease]; // 再建立一个自动释放池2 @autoreleasepool { Person *person2 = [[[Person alloc] init] autorelease]; } Person *person3 = [[[Person alloc] init] autorelease]; }
释放的顺序就是person2->person->person3,先释放内层的,再释放外层的,同一层的从上到下释放。
自从ARC出来以后,iOS开发内存管理便方便不少,总结要点以下:
1.__strong:表示引用为强引用。对应在定义property时的"strong"。全部对象只有当没有任何一个强引用指向时,才会被释放。若是属性前面不加修饰符,默认的引用方式就是强引用,当须要释放强引用指向的对象时,须要将强引用置nil。
2.__weak:表示为弱引用,弱引用不会影响到对象的释放,就算有一百个弱引用指向某个对象,对象依然会被释放(当没有任何一个强引用指向该对象的时候),可是当对象被释放以后,全部志向该对象的弱引用将会被置为nil。弱引用能够防止循环引用,好比delegate就是使用的弱引用。
3.__autoreleasing:表示在autorelease pool中自动释放对象的引用,和MRC时代autorelease的用法相同。定义property时不能使用这个修饰符,任何一个对象的property都不该该是autorelease型的。如下两行代码的意义是相同的。
NSString *str = [[[NSString alloc] initWithFormat:@"hehe"] autorelease]; // MRC NSString *__autoreleasing str = [[NSString alloc] initWithFormat:@"hehe"]; // ARC
4.声明IBOutlet时通常应当使用weak,除了对StoryBoard这样nib中间的顶层对象要用strong
5.weak至关于老版本的assign,strong至关于retain,copy的做用和原来同样
6.不能直接调用dealloc方法,不能调用retain,release,autorelease,retainCount方法,包括@selector(retain)的方式也不行
7.能够用dealloc方法来管理一些资源,但不能用来释放实例变量,也不能在dealloc方法里面去掉[super dealloc]方法,在ARC下父类的dealloc一样由编译器来自动完成