前面我们已经说过,OC不同于Java的地方就是没有垃圾回收机制,在内存管理这块,cocoa引入了一种称为引用计数(reference counting)的技术,有时也叫保留计数,每个对象有一个与之对关联的整数,称作它的引用计数器或保留计数器.当某段代码要访问一个对象的时候,该代码将该对象的保留计数值加1,表示”我要访问该对象”,当这段代码结束对象访问时,将对象的保留计数值减1,表示它不再访问该对象,当保留计数值为0时,表示不再有代码访问对象了,对象被销毁,其占用的内存被系统回收。
我来简单说一下原理:
1、每个对象内部都保存了一个与之关联的整数,称之为引用计数器,当使用alloc、new或者copy创建一个对象时,对象的引用计数器被设置为1;
2、给对象发送一个retain消息(调用retain方法),可以使计数器+1;
3、给对象发送一个release消息(调用release方法)或者autorelease消息,可以使计数器-1;
4、当一个对象的引用计数为0时,那么他将被销毁,其占用的内存被系统回收,OC也会自动向对象发送一条dealloc消息,一般会重写dealloc方法,在这里释放相关资源,一定不要直接调用dealloc方法。
5、发送retainCount消息获得当前的引用计数器的值。
注:我们这里说的发送消息就是调用方法
- (id)retain; // 计数器+1
- (void)release; //计数器-1
- (id)autorelease;//计数器-1
- (unsigned)retainCount;//获得当前引用计数器的值
在这里大家就会疑惑了,怎么的对象才需要我们管理内存呢?可以这么说,任何继承了NSObject的对象都需要管理内存。基本数据类型,像int ,float,double,int类型的指针数组什么的都不需要管理内存。
我们来看一下例子依照惯例,我们还是来创建一个类:
Student.h
#import<Foundation/Foundation.h>
@interface Student :NSObject
@property int age; //声明一个getter方法、setter方法
@end
Student.m
#import "Student.h"
@implementation Student
@synthesize age=_age; //在xcode4.5环境下可以省略
//验证对象有没有被回收
-(void)dealloc
{
NSLog(@"%@被销毁了",self);//验证对象有没有被回收
[super dealloc];//一定要到调用super的dealloc方法,而且最好是在最后调用
}
@end
我们在main.m中测试一下
#import<Foundation/Foundation.h>
#import"Student.h"
int main(int argc,const char *argv[])
{
@autoreleasepool{
Student *stu=[[Student alloc]init];//调用了alloc方法,计数器为1
[stu release];//释放,计数器为0;
}
return 0;
}
在前边我们有提到,在销毁对象的时候,OC也会自动向对象发送一条dealloc消息,一般会重写dealloc方法,在这里释放相关资源,一定不要直接调用dealloc方法。所以我们用dealloc方法来验证对象是否被销毁。
如果对象被回收以后(retainCount=0),再发送一条release消息,就会发生野指针错误。
#import<Foundation/Foundation.h>
#import"Student.h"
int main(int argc,const char *argv[])
{
@autoreleasepool{
Student *stu=[[Student alloc]init];//调用了alloc方法,计数器为1
[stu release];//释放,计数器为0
[stu release];//计数器为0,再次释放则会发生野指针错误,也就是说访问了你不该访问的内存
}
return 0;
}
autorelease的实现
还有一种情况,如果方法名并不以alloc、new、copy开头,比如:
+ (NSArray *)array
{
return [[NSArray alloc] init] autorelease];
}
程序内部调用了alloc,就需要调用release来释放,所以我们采用了一种自动释放机制autorelease,其中具体原理先不深究,后面我会详细讲解。
内存管理原则:
1、谁创建,谁释放(“谁污染,谁治理”),如果你通过alloc、new或者copy来创建一个对象,那么你必须调用release或者autorelease来释放,换句话说,不是你创建的,你就不用释放
2、一般来说,除了alloc、new或者copy之外的方法创建的对象,都被声明了autorelease
3、谁retain,谁release,无论这个对象是怎样生成的
视频链接
http://pan.baidu.com/s/1ntMpRQT