对象的创建是一件消耗资源的事情,所以,在对象使用后,要将对象及时从内存中释放掉。 为了管理对象的创建和释放,在iOS中,我们引入了“引用计数”这一技术。
下面我们通过一个生活中的例子,来形象的说明引用计数是怎么一回事。
我们可以把房间里的灯看做对象,灯亮着,表示该对象正在被使用;灯灭了,表示该对象被释放掉了。 当有人进入房间里,打开灯,离开屋子,关掉灯。好,规则就是这样,现在来它是怎么运作的。
第一个人进入房间,“需要照明的人数”是1,此时引用计数值是从0变成了1,因此要开灯,相当于要创建对象。
第二个人进入房间,“需要照明的人数”是2,此时引用计数值是从1变成了2,由于灯已开,相当于持有对象。
有一个人离开房间,“需要照明的人数”变成1,此时引用计数值是从2变成了1。 由于对象的引用计数不为0,所以不能关灯(不能释放对象),如果此时关灯,会影响到在屋子里的另外一个人。
最后一个人离开房间,“需要照明的人数”变成0,此时引用计数值是从1变成了0。需要关灯,相当于释放了对象。
通过这个例子,我们可以很直观的知道,引用计数其实就是对象被多少人使用。 如果对象在被使用,则不能释放,如果没有人使用,则对象会被释放掉。
在我们实际写程序时,会遵循下面的几个原则:
相对应的objective-c方法:
用new/alloc/copy/mutableCopy开头的方法名创建的对象,意味着自己持有该对象。
这里有一个编写方法的默认约定,如果以上面4个关键字开头命名的方法,返回的对象会自动持有,应该这样写:
- (id)allocObject {
id obj = [[NSObject alloc] init];
return obj;
}
// 创建对象,并自动持有
id a = [XX allocObject];
// 使用完毕后,释放对象
[a release];
如果不是以上面4个关键字作为开头命名的方法,返回的对象不会被自动持有,应该这样写:
- (id)createObject {
id obj = [[NSObject alloc] init];
// 对象调用autorelease方法,放入自动释放池。
// 关于autorelease,稍后会提及到。
return [obj autorelease];
}
// 创建对象,由于是autorelease的对象,所以,不持有该对象
id a = [XX createObject];
// 保持对象
[a retain];
// 释放对象
[a release];
// 由于不是由alloc/new/copy/mutableCopy开头的方法名创建的对象,自己不持有该对象
id obj = [NSMutableArray array];
// 所以,要持有该对象
[obj retain];
// 使用该对象
[obj ...];
// 使用完毕,释放对象
[obj release];
// 由于不是由alloc/new/copy/mutableCopy开头的方法名创建的对象,自己不持有该对象
id obj = [NSMutableArray array];
// 没有持有该对象,释放对象导致程序崩溃
[obj release];
autorelease能够在对象超出生命周期之后,能正确自动的释放对象。 调用release会让对象的引用计数减1,如果计数值减到0,则对象会立即释放。 但autorelease则不然,对象不会被立即释放,调用autorelease会将对象注册到自动释放池中,等到自动释放 池被pool时,所有池中的对象都会被调用release方法,进行释放。 所以,可以看出,release与autorelease的不同之处就在于,一个是立即释放,一个则不是。
说到自动释放,就不能不提自动释放池–autoreleasepool。 autoreleasepool可以看做变量的作用域,autorelase的对象,超出这个范围,就会被释放。
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain];
ARC是一种编译器技术,将以前人工持有、释放对象的过程,交由编译器来做。减小了内存泄露和对象过度释放的情况的发生, 极大地提高了开发效率。
__strong是默认的修饰符,例如我们定义的对象,即使不指明__strong,也默认是__strong修饰符来修饰的。
id obj = [NSObject new];
// 等价于
id __strong obj = [NSObject new];
__weak是为了解决对象之间循环引用而引入的修饰符。用__weak修饰的对象,只是简单的将指针指向对象,但引用计数不加1。 但对象被释放后,指针将被指向nil。
作用同__weak,但适用于在iOS SDK4.0之前。与__weak的区别在于,如果对象被释放,则指针会变成野指针。
在ARC中,不能使用autorelease关键字,但autorelease功能是起作用的。所以,需要使用__autorelieasing修饰符。
@autoreleasepool {
id __autoreleasing obj = [[NSObject alloc] init];
}
--EOF--