Objective-C内存管理
1. Objective-C指针赋值时,retainCount不会自动增加,需要手动retain。
1 ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1 2 ClassA *obj2 = obj1; //retain count = 1 3 [obj2 retain]; //retain count = 2 4 [obj1 hello]; //输出hello 5 [obj1 release]; //retain count = 2 – 1 = 1 6 [obj2 relese]; //retain count = 0,对象被销毁
2. 新生成的对象只要调用autorelease就行了,无需再调用release!自动释放的对象不需要调用release,因为已经将释放的责任转交给了自动释放池。但是对于赋值的指针还是要调用release的!
1 ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1 2 ClassA *obj2 = obj1; //retain count = 1 3 [obj2 retain]; //retain count = 2 4 [obj1 hello]; //输出hello 5 //对于obj1,无需调用(实际上不能调用) 6 release [obj2 hello]; //输出hello 7 [obj2 release]; //retain count = 2-1 = 1
3. NSAutoreleasePool内部包含一个数组(NSMutableArray),用来保存声明为autorelease的所有对象。如果一个对象声明为autorelease,系统所做的工作就是把这个对象加入到这个数组中去。NSAutoreleasePool自身在销毁的时候,会遍历一遍这个数组,release数组中的每个成员。如果此时数组中成员的retain count为1,那么release之后,retain count为0,对象正式被销毁。如果此时数组中成员的retain count大于1,那么release之后,retain count大于0,此对象依然没有被销毁,内存泄露。
而自动释放池之间以栈的形式实现:当你创建了一个新的自动释放池时,它被添加到栈顶。接受autorelease消息的对象将被放入最顶端的自动释放池中。如果将一个对象放入一个自动释放池中,然后创建一个新的自动释放池,再销毁新建的自动释放池,则这个自动释放池对象仍将存在,因为容纳该对象的自动释放池仍然存在。
4. Objective-C程序中可以嵌套创建多个autorelease pool。在需要大量创建局部变量的时候,可以创建内嵌的autorelease pool来及时释放内存。一般都是使用完对象之后马上进行释放,以将内存使用量保持在尽可能低的水平。
5. 如果你通过alloc、new或copy来创建一个对象,如果是临时对象,那么你必须在不再使用时手动调用release或autorelease来释放对象;如果希望在多段代码中一直拥有对象,作为其他对象的实例来使用,则只需确保在拥有该对象的dealloc方法中释放它即可。除了alloc、new或copy之外的方法创建的对象都被声明了autorelease。
6. 谁retain,谁release。只要你调用了retain,无论这个对象是如何生成的,你都要调用release。
7. 范式:Release一个对象后,立即把指针清空(顺便说一句,release一个空指针是合法的,但不会发生任何事情)。
1 [obj1 release]; 2 obj1 = nil;
1 ClassA *obj2 = obj1; 2 [obj2 retain]; 3 //do something 4 [obj2 release]; 5 obj2 = nil;
8. 范式:在方法中创建的临时对象,在方法返回前需要对其进行释放。
在一个函数中创建并返回对象,需要把这个对象设置为autorelease。这样,由于延迟释放,返回的对象不仅有效,而且保证会被自动释放池释放。
1 ClassA *Func1() 2 { 3 ClassA *obj = [[[ClassA alloc]init]autorelease]; 4 return obj; 5 }
如果程序的某个方法中需要创建很多临时对象,当方法执行完之后这些临时对象就没用了。如果整个程序只有一个释放池,则这些临时对象会一直无法释放,直至事件处理结束。所以,可以在方法的开始处或循环中创建一个局部的自动释放池,在方法返回或退出循环之前释放自动释放池。这样所有该方法创建的临时对象会随着自动释放池的释放而释放。使用@autoreleasePool{},无须显示向某对象发送autorelease方法,所有花括号里的代码都会被自动放入这个新池子里,任何在花括号里定义的变量在括号外就无法使用了。
1 int main (int argc, const char *argv[]) 2 { 3 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 4 int i, j; 5 for (i = 0; i < 100; i++ ) 6 { 7 @autoreleasePool 8 { 9 for (j = 0; j < 100000; j++ ) 10 [NSString stringWithFormat:@"1234567890"];//产生的对象是autorelease的。
12 } 13 } 14 return (0); 15 } // main
9. 范式:在子类的dealloc方法中调用基类的dealloc方法 。
1 -(void) dealloc 2 { 3 … 4 [super dealloc]; 5 }
10. 范式:如果类中声明了具有保持copy和复制retain特性的属性,则需要在dealloc方法中release其成员变量。
1 @interface ClassA : NSObject 2 { 3 ClassB* _objB; 4 } 5 @property (retain) ClassB* objB; 6 @end 7 8 @implementation ClassA 9 @synthesize objB; 10 -(void) dealloc 11 { 12 [_objB release]; 13 [super dealloc]; 14 } 15 @end
11. 范式:除了dealloc方法以外,始终用.操作符的方式来调用property。
1 self.objB 或者 objA.objB
12. 自己管好自己就行。如果获得了一个其他方法提供的对象,则不需要考虑该对象的内存管理问题,不必执行任何操作。但是,如果想要在一段时间内使用该对象,则需要保留retain该对象,并在使用完成后(在dealloc方法中)将其释放release。必须保持retain方法和release方法的使用次数相等。