内存管理对于Objective-C来说真是一个复杂的问题,很多时候我们要弄清楚某个对象的所有权归属并不容易,由此造成难以找到合适的释放对象的方法。
但Cocoa中有一个自动释放池的概念给我们提供了便利。
NSObject类提供了一个autorelease方法,该方法预先设定了一条会在未来某个时间发送的release消息,其返回值是接收这条消息的对象:
- (id) autorelease;
当给一个对象发送autorelease消息时,实际上是将该对象添加到了自动释放池中。
当自动释放池被销毁时,会向该池中的所有对象发送release消息。
使用NSAutoreleasePool对象可以创建一个自动释放池,在创建和释放NSAutoreleasePool对象之间的代码都会使用该池:
NSAutoreleasePool *pool;
pool = [NSAutoreleasePool new];
//Coding in here...
[pool release];
在我们创建基于Foundation的项目时,其实编译器已经自动帮我们创建了@autorelease的自动释放池:
#import
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
}
return 0;
}
1、当我们把代码写在@autoreleasepool的花括号里时,所有的代码都是自动释放的;
2、任何在@autoreleasepool的花括号定义的变量,在括号外是无法使用的,类似于C语言的数据有效范围;
3、iOS 5.0之后已经淘汰使用NSAutoreleasePool对象创建自动释放池的方法,因为@autoreleasepool更直观,而且Objective-C语言创建和释放内存的能力远在我们之上。
4、autorelease只是把对象扔到自动释放池里面(延迟了对象被销毁的时间),并不可以改变对象的计数器;
5、改变计数器只有retain和release两种方法;
6、autorelease和release不能同时存在:
autoreleasepool{
Car *c = [[[Car alloc] init] autorelease];
[c release];
}
//错误!!!
//对对象执行二次释放会出现野指针错误!!!
7、autoreleasepool是以栈结构存在的,栈结构的特点就是先进后出;
8、autorelease的缺点是不能精确控制对象被销毁的时间,内存处理效率低(适用于占用内存比较小的对象,对象里面包含的属性主要是基本数据类型)。如果是在一个循环中出现大量的迭代,必须自己在循环中创建一个自动释放池来定期清理:
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
int i;
for (i = 0; i < 1000000; i++) {
id object = [someArray objectAtIndex: i];
NSString *desc = [object descrption];
// and do something with the description
if (i % 1000 == 0) {
[pool release];
pool = [[NSAutoreleasePool alloc] init];
}
}
[pool release];
9、在调用函数的过程中自动释放池不会被销毁,程序不会随即销毁自动释放池,因此不必保留使用的每一个对象;
10、自动释放池被清理的时间是完全确定的:要么在代码中自己手动销毁,要么是使用APPKit时在时间循环结束时销毁。