引用计数器
基本结构
-
每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即该对象被多少个对象在引用
-
每个OC对象内部专门有4个字节来存储引用计数器
引用计数器的作用
当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认为1
当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收,如果不为0,那么在整个程序运行过程中始终占据内存空间,除非整个程序退出。
引用计数器的操作
1) 给对象发送一条retain消息,可以使引用计数器+1(retain方法返回值为对象本身)
2) 给对象发送一条release消息,可以使引用计数器-1(没有返回值)
3) 可以给对象发送retainCount消息获得当前的引用计数器值
4) dealloc
-
当一个对象要被回收的时候,就会调用dealloc
-
重写dealloc方法时,一定要调用[super dealloc],且必须放在最后面
野指针:指向僵尸对象(不可用内存)的指针
僵尸对象:所占内存已经被回收的对象,僵尸对象不可再使用
空指针:没有指向任何东西的指针(存储的东西是nil、NULL、0)
多对象内存管理
1) 你要使用(占用)某个对象(set一个对象),就应该让对象的计数器+1(让对象做一次retain操作)
2) 你不再使用(占用)某个对象,就应该让对象的计数器-1(让对象做一次release)
3) 谁retain,谁release
4) 谁alloc,谁release
内存管理代码规范
只要调用了alloc,必须有release(autorelease)
没有调用alloc,就没有release(特殊对象:NSString对象,它不调用alloc,为直接赋值字符串对象)
set方法的代码规范
- 基本数据类型
直接操作即可
- OC对象类型
- (void)setCar:(Car *)car { //1.先判断是否为新传进来的对象 if(car!=_car) { [_car release];//(释放旧对象,执行release)换车时需对原来的车对象引用计数器进行-1 _car=[car retain];//拥有一个新对象,对新对象做一次retain } }
dealloc方法的代码规范
-
对将收回的对象所拥有的其他对象进行释放,执行release(没有对象引用,就没有release,如:单个对象)
-
必须执行[super dealloc]
@Property的参数(即:带参数的@Property)
@Property所带的参数分为以下四类:
set方法内存管理相关的参数
-
retain :自动生成内存管理规范的set方法,即:release旧值,retain新值(适用于OC对象类型),如:@Property(retain) Car *car;
-
assign :直接赋值(默认,适用非OC对象类型)
-
copy :release旧值,copy新值
是否要自动生成set方法
-
readwrite:同时生成setter和getter的声明、实现(默认就是)
-
readonly:只生成getter的声明、实现
是否自动生成带有多线程管理
-
nonatomic:性能高(通常用这种)
-
atomic:性能低(默认)
是否自定义自动生成的setter和getter方法的名称
-
setter:自定义set方法的名称,注意带冒号:如:@property (setter=other age:) int age;
-
getter:自定义get方法的名称,(通常用于BOOL类型)
循环retain和@class
@class
作用:仅仅告诉编译器,某个名称是一类
开发中引用一个类的规范
在.h文件中用@class来声明类
在.m文件中用#import来包含类的所有东西
两端循环引用(即:你中有我,我中有你)解决方案
一端用retain,另一端用assign,否则会造成两个对象都无法被收回内存
autoreleasepool(自动释放池)
基本使用(autoreleasepool)
-
会将对象放到一个自动释放池中
-
当自动释放池被销毁时,会对池子里面的所有对象执行一次release操作
-
会返回对象本身
-
自动释放池存储于栈结构中
例
@autoreleasepool{
Person *p=[[[Person alloc] init] autorelease];
}
好处
-
不用关心对象释放的时间
-
不用关心对象什么时候调用release
使用注意
-
当对象占用内存空间较大时(如对象的成员变量有很多其他引用对象),不要使用自动释放池,应该使用release精确控制
-
当对象占用内存的对象较小时,可以使用自动释放池,影响不大
实例
经验写法:
-
开发中经常自定义一个类方法,这个类方法返回拥有引用自动释放池的对象,同时也可以传入一些参数
-
创建对象的时候不要直接用类名,要用self(这样即使子类直接调用也不影响)
如:Person类
自定义类方法:
+ (id)person
{
retrun[[[self alloc] init] autorelease];
}
根据需要也可自定义返回成员变量已拥有一定值的类方法
+(id)personWithAge:(int)age
{
Person*p=[self person];
p.age=age;
return p;
}
编译器特性-ARC
基本原理
ARC判断准则:只要没有强指针指向对象,就会释放对象
指针分两种:
强指针:默认情况下,所有的指针都是强指针。定义格式:_ _strong
弱指针:_ _weak
ARC特点
不允许调用release、retain、retainCount
允许重写dealloc,但不允许调用[super dealloc]
- @proerty参数
strong:成员变量是强指针
weak:成员变量是弱指针
assign:同非ARC
ARC中的strong等价于非ARC中的retain
- 循环调用
ARC中循环调用:一端用strong,另一端用weak