OC内存管理
一、基本原理
(一)为什么要进行内存管理。
由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量等。
管理范围:任何继承NSObject的对象,对其他的基本数据类型无效。
本质原因是因为对象和其他数据类型在系统中的存储空间不一样,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的所有局部变量会被回收,指向对象的指针也被回收,此时对象已经没有指针指向,但依然存在于内存中,造成内存泄露。
(二)对象的基本结构
每个OC对象都有自己的引用计数器,是一个整数表示对象被引用的次数,即现在有多少东西在使用这个对象。对象刚被创建时,默认计数器值为1,当计数器的值变为0时,则对象销毁。
在每个OC对象内部,都专门有4个字节的存储空间来存储引用计数器。
(三)引用计数器的作用
判断对象要不要回收的唯一依据就是计数器是否为0,若不为0则存在。
(四)操作
给对象发送消息,进行相应的计数器操作。
alloc用来创建对象,创建对象后,引用计数为1,只调用一次。
Retain消息:使计数器+1,该方法返回对象本身,可多次调用。
Release消息:使计数器-1(并不代表释放对象),可调用多次。
retainCount消息:获得对象当前的引用计数器值。
当引用计数为0的时候,对象会被系统从内存中销毁,销毁之前会自动调用该对象的dealloc方法。
(五) 对象的销毁
当一个对象的引用计数器为0时,那么它将被销毁,其占用的内存被系统回收。
当对象被销毁时,系统会自动向对象发送一条dealloc消息,一般会重写dealloc方法。dealloc就像是对象的“临终遗言”。一旦重写了dealloc方法就必须调用[super dealloc],并且放在代码块的最后调用(不能直接调用dealloc方法)。
-(void)dealloc{
NSLog(@“妈的,我被销毁了。”);
[super dealloc];
}
一旦对象被回收了,那么他所占据的存储空间就不再可用,坚持使用会导致程序崩溃(野指针错误)。
二、对象所有权
当一个所有者(本身是一个OC对象),当它做了如下的动作,它就拥有了一个对象的所有权:
alloc retain 【mutable】copy
使用如下方法释放所有权:
release autorelease
三、相关概念和使用注意
野指针错误:访问了一块坏的内存(已经被回收的,不可用的内存)。
僵尸对象:所占内存已经被回收的对象,僵尸对象不能再被使用。(打开僵尸对象检测)
空指针:没有指向任何东西的指针(存储的东西是0,null,nil),给空指针发送消息不会报错
注意:不能使用[p retaion]让僵尸对象起死复生。
四、内存管理原则
(一)原则
只要还有人在使用某个对象,那么这个对象就不会被回收;
只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;
当你不想使用这个对象时,应该让对象的引用计数器-1;
(二)谁创建,谁release
(1)如果你通过alloc,new,copy来创建了一个对象,那么你就必须调用相应的release或者autorelease方法将其释放
(2)不是你创建的就不用你去负责
(三)谁retain,谁release
只要你调用了retain,无论这个对象时如何生成的,你都要调用release
(四)总结
有始有终,有加就应该有减。曾经让某个对象计数器加1,就应该让其在最后-1.
五、内存管理代码规范
(一)只要调用了alloc,就必须有release(autorelease)
(二)Set方法的代码规范
(1)基本数据类型:直接复制
-(void)setAge:(int)age
{
_age=age;
}
(2)OC对象类型
-(void)setCar:(Car *)car
{
//1.先判断是不是新传进来的对象
If(car!=_car)
{
//2 对旧对象做一次release
[_car release];//若没有旧对象,则没有影响。不要纠结这句话,没有旧对象就是没有影响,想明白怎么回事就去看API啊。
//3.对新对象做一次retain
_car=[car retain];
}
}
(三)dealloc方法的代码规范
(1)一定要[super dealloc],而且要放到最后//[super dealloc]是调用父类的dealloc方法,让父类释放父类所持有的对象
(2)对self(当前)所拥有的的其他对象做一次release操作(解释一下,当一个对象用到dealloc方法的时候,就是说明该对象的引用计数为0了,要释放这个对象所占用的空间了,如果释放了这个对象,那么这个对象本身要是还有别的对象存在的话,就没有任何意义了,所以要对self所拥有的其他对象进行relase)
-(void)dealloc
{
[_car release];
[super dealloc];
}
六、@property的参数
举一个例子:在类的声明文件(.h文件)写类方法的地方(大括号外面)有:
@property(Nonatomic,copy,ReadWrite) NSString *strName;
那么@property会自动生成一个_strName(带下划线的属性)属性,并且为该属性生成set和get方法。但是是默认的不会显示出来。如果想让@property生成的名字有所改动的话,可以在.m文件里面使用@synthesize后面加新的属性名的形式更改生成的属性名字。(@synthesize strName = ¥¥¥¥;)那么@property NSString *strName;生成的属性名字就是¥¥¥¥了。
1 多线程管理(苹果在一定程度上屏蔽了多线程操作)
Nonatomic:高性能,一般使用这个
Atomic:低性能(默认的)
2.@property创建属性一共有三种形式(想要哪种形式就在@property(1,2,3)这里设置):
(1).普通的赋值形式:Assign:直接赋值(默认,适用于非oc对象类型)
-(void)setStrName{
-strName = strName;
}
(2).第二种形式是retain,Retain:对对象release旧值,retain新值(适用于OC对象类型)
-(void)setStrName
{
if(_strName!=strName)
【_strName release】;
_strName = [strName retain];
}
(3).第三种形式是copy:Copy:release旧值,copy新值(OC中NSString对象的引用计数持有,用copy)
-(void)setStrName
{
if(_strName!=strName)
【_strName release】;
_strName = [strName copy];
}
3.是否要生成set方法(若为只读属性,则不生成)
Readonly:只读,只会生成getter的声明和实现
Readwrite:默认的,同时生成setter和getter的声明和实现
(4)Set和get方法的名称
修改set和get方法的名称,主要用于布尔类型。因为返回布尔类型的方法名一般以is开头,修改名称一般用在布尔类型中的getter。
@propery(setter=setAbc,getter=isRich) BOOL rich;
BOOL b=p.isRich;// 调用