内存管理
1、基本知识
2、关闭ARC机制
3、@property
4、循环引用
5、自动释放池
一、基本知识
内存的分类
栈:局部变量
堆:动态申请的对象,变量等
全局(静态):static 变量,const变量,全局变量等
引用计数器
每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象
每个OC对象内部专门有4个字节的存储空间来存储引用计数器
作用
当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1
当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。换句话说,如果对象的计数器不为0,那么在整个程序运行过程,
它占用的内存就不可能被回收,除非整个程序已经退出。
引用计数器的操作
1、给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)
2、给对象发送一条release消息,可以使引用计数器值-1
3、可以给对象发送retainCount消息获得当前的引用计数器值
总结:有始有终,有加有减。
二、关闭ARC机制
如果要自己调用release等函数,需要关闭ARC功能,关闭方法参考
http://jingyan.baidu.com/article/358570f67babbcce4724fcd8.html
管理方式set方法加1,dealloc 减1
1、想使用某个对象,就应该让对象的计数器加1(retain)
2、不想再使用某个对象时,就应该让对象的计数器减1 (release)
2、谁retain谁release,谁alloc谁release
内存管理规范:
1、只要调用alloc必须有release,如果不是alloc那就不需要release
2、set 方法
基本数据类型直接赋值
OC对象类型。
先判断是不是同一个对象 if(car != _car)。
然后对旧对象release,对新车进行一次retain操作。
3、dealloc
一定要调用[super dealloc],而且放到最后边
一定要当前对象release一次
三、@property
@property // 默认是赋值,retain 参数实现内存管理
@property int age; // 默认是赋值 @property(retain) Book * book; // retain 参数实现内存管理
内存管理总结:
1、内存管理的相关参数
retain :release旧值,retain新值
assign :直接赋值,默认就是这个,适用于非OC对象类型
copy :release旧值,copy新值
2、是否要生成set方法
@property (readonly) int age; // 只读,只生成getter方法
@property (readwrite) int name; // 读写,默认是读写
3、多线程管理
nonautomic : 性能高,
automic : 性能低(默认)
@property (nonautomic , assign) int age; // 以后这样写
4、setter和getter方法的名称
@property (setter = myAge:) int age; // setter = set方法名 ,自定义setter方法名,不要忘记冒号
@property (getter = getAge) int age; // getter = get方法名 ,自定义getter方法名
@property (getter = isRich) BOOL rich; // 一般这个会用在BOOL类型的变量声明,getter方法名以is开头
四、循环引用
类A引用类B,类B引用类A。
解决方法: @class A;// 仅仅告诉编译器A是一个类
在类引用前,在声明文件里使用关键字@class A;
@class 和#import区别
1、#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在A.h文件中 B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息
2、如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来 讲,使用@class方式就不会出现这种问题了
3、在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类
在开发中引用一个类的规范
1、在.h文件中用@class来声明类
2、 在.m文件中用#import 来包含类的所有东西
3、 循环retain的解决方案
一端用retain,一端用assign
五、自动释放池
autorelease 基本用法
1、会将对象放到一个自动释放池中
2、当对象释放池被销毁时,会自动释放里面的所有对象(release操作)
3、会返回对象自身
4、调用autorelease后,对象的计数器不变
好处
1、不用再关心对象释放的时间
2、不用再关心什么时候调用release
注意事项
1、占用内存较大的对象不要随便使用autorelease
2、占用内存较小的使用autorelease,没有太大影响
3、autorelease和release一样,也是和alloc/new/copy一一对应
1 @autoreleasepool // 自动释放池 2 { 3 Person *p = [[[Person alloc] init] autorelease]; // autorelaese 方法返回对象本身,计数器并不会立即改变 4 Card *c = [[[Card alloc] init] autorelease]; 5 6 p.card = c; 7 c.person = p; 8 9 @autoreleasepool // 可以嵌套 10 { 11 12 Person *p = [[[Person alloc] init] autorelease]; 13 Card *c = [[[Card alloc] init] autorelease]; 14 15 16 p.card = c; 17 c.person = p; 18 19 20 } 21 22 }