每个对象都有自己的引用计数器
每一个引用计数都占4个字节存放自己的引用计数器
当计数器为0的时候就会回收,对象刚建立的时候计数器数值为1
计数器的操作:
1:给对象发送一条retain消息,可以使引用计数器数值+1(retain方法返回对象本身)
2:给对象发送一条release消息,可以使计数器数值-1
3:可以给对象发送retainCount消息获得当前的引用计数器数值
对象的销毁:
1:当计数器为0 的时候,那么它将被销毁,其占用的内存被系统回收。
2:当对象被销毁时,系统会自动向对象发送一条- dealloc消息
3:一般会重写- dealloc方法,在这里释放相关资源,- dealloc就像是对象的遗言
4:一旦重写了- dealloc方法就必须调用[super dealloc]并且放在最后面调用
5:不要直接调用dealloc方法
6:一旦对象被系统回收,它占用的内存就不可在用,坚持食用会造成系统崩溃(野指针错误)
这些方法都是对象方法。
野指针:指向僵尸对象或者(不可用内存)的指针
//错误提示:EXC-BAD-ACCESS:访问了一块坏内存(已经被回收,不可用的内存)也称为野指针错误
当计数器为0之后要将指针指向赋值为nil:p = nil;
空指针:没有指向任何东西的指针,(存储的东西是nil,NULL,0)给空指针发送消息不会报错
多对象内存管理:
1:谁创建谁release
如果你通过alloc new 或者[mutable]copy来创建一个对象,那么你必须调用release或者autorelease,换句话说不是你创建的你就不用去[auto]release
2:谁retain谁release
只要你调用了retain,无论这个对象是如何生成的,你都要调用release
3:总结。
1:有始有终,有加有减
2:曾经让对象的计数器+1,最后就必须让对象的计数器-1
内存管理规范:
1:只要调用了alloc就必须要有release或者autorelease
2:set方法代码规范:
1:基本数据类型直接复制
2:oc对象
- (void)setCar:(Car*)car
{//首先判断是不是新传进来的对象
if(car !=_car)
{
[_car release]; // 旧对象做一次release
[car retain]; // 对新对象进行一次retain
}
}
dealloc方法代码规范:
1:一定要[super dealloc],而且放到最后面
2:对self(当前对象)所拥有的其他对象进行一次release
- (void)dealloc
{
[_car release];
[super dealloc];
}
如果对象不是通过alloc创建的就不需要release
@property的内存管理:
@property(retain)Book*book;
缺点:dealloc方法还是要自己写
property的参数:
1:内存管理相关的参数
retain:release旧值,retain新值
assign:直接赋值,适用于oc非对象类型
copy:release旧值,copy新值
2:是否要生成set方法
readonly:只会生成getter的声明和实现
readwrite:同时声明setter和getter方法声明和实现
3:多线程管理
nonatomic:性能高(一般就用这个)
atomic:性能低(默认)
4:setter和getter方法的名称
@property(getter =方法名称)int weight
@property(setter =方法名称:)int weight
一般用在BOOL类型的get方法
返回BOOL类型的方法名一般以is开头,所以可以利用这个来修改get方法的方法名
@class仅仅是告诉编译器后面的只是一个类
@class Person 仅仅告诉编译器Person仅仅是一个类
循环调用的时候在声明中用class声明是一个类
在实现中真正用到这个类的时候再导入需要用到的该类
开发中的规范:
1:在.h文件中用@class来声明一个类
2:在.m文件中再用@import导入该类的.h文件
循环引用不能释放的问题怎么解决?
1:一端用retain
2:一端用assign(assign是直接赋值,没有retain和release所以在创建和释放计数器是1变成0,这样另一个oc对象就可以释放了。)
例子:比如身份证和人的关系。
autorelease:
autorelease方法会返回对象本身。
Autorelease会将对象放到一个自动释放池中
当自动释放池销毁时会对池子里面的所有对象进行一次release操作
Person *p = [[[Person alloc] init] autorelease]
autorelease对象的计数器不变
@autoreleasepool
{
// { 开始代表创建了释放池
// }结束代表销毁释放池
}
将对象放在{}中间
释放池的释放顺序是栈的结构释放,先进后出
我们在程序运行的时候可以创建无数了释放池,释放顺序是先进后出的顺序。
autorelease只是延迟了对象释放的时间。
autorelease不能精确控制对象释放的时间,所以只适合占用内存比较小的时候。
Autorelease好处:
不用在关心对象释放的时间
不用关心什么时候调用release
autorelease注意点:
占用内存比较打的对象不要随便用autorelease
占用内存较小的对象使用autorelease,没有太大影响
autorelease常见错误:
alloc之后调用了autorelease之后又调用了release是错误的
连续调用多次autorelease也是错误写法。
开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象
创建对象时不要直接使用类名,一般用self
+(id)person
{
return[[[self alloc] init] autorelease];
}
如果创建对象的时候retain一次,那么就必须在delloc方法泗洪release一次
property(retain)只是替代了set方法中的retain和release
释放池autorelease只是代替了对象创建时alloc对应的release
也就是[Person release];