手工管理内存计数
概念
当创建对象时,初始的引用计数为1。每当创建对象的引用时对象引用计数应+1。可以给对象发送retain消息。
[myFraction retain];
当不需要对象时,通过发送release消息,为引用计数-1。
[myFraction release];
当引用计数为0时,系统就知道这个对象不再需要使用了,所以可以释放它的内存。
通过给对象发送dealloc(NSObject)消息释放它的内存。
为了能够释放由对象创建或保持的实例变量或者其他对象,需要覆盖dealloc方法。
当使用手工内存管理引用计数时应注意Foundation框架中的一些方法可能会增加对象的引用计数(UIView的addSubView等)。有些方法会减少对象到引用计数(removeFromSuperView:)。
当对象被销毁后,对象的引用失效,这样的指针称为悬挂指针。给悬挂指针发送消息会导致程序崩溃。对对象的过度release操作会造成程序的崩溃。
对象引用和自动释放池
开发过程中经常会遇到如下问题:创建一个对象,然后将它作为方法调用的结果返回。这样尽管方法不再使用它,但是却不能释放它。NSAutoreleasePool类可以解决这类问题。
-将对象加入自动释放池
[result autorelease];
-创建自动释放池
NSAutoreleasePool pool = [[NSAutoreleasePool alloc]init];
-清理自动释放池
清理自动释放池会对池内的对象进行release操作。
[pool drain];
注意[1]:使用来自Foundation,UIKit,AppKit等框架中的类时,需要先创建一个自动释放池,因为来自这些框架的类会创建并返回自动释放对象。
注意[2]:并不是所有新创建的对象都会添加到自动释放池中,凡是以alloc, new, copy, mutableCopy为前缀的方法创建的对象都不会被自动释放。
注意[3]:方法A中创建了一个对象,并将该对象作为方法的返回值返回给调用的方法,return之前不能对对象进行release操作,这样会使得返回的对象指针为悬挂指针。正确的处理方式为return [result autorelease];
事件循环和内存分配
事件是伴随着某些行为而发生的。ios应用和Cocoa应用运行在事件循环中。为了处理一个新的事件,系统会自动创建一个内存释放池,可能会调用到应用中的一些方法来处理这个事件。当事件处理结束,系统开始等待下一个事件,然后在此之前,系统会清理自动释放池。意味着:事件处理工程中创建的自动释放池被释放,池内的对象将销毁。除非对象使用retain操作,才能从清空到释放池中幸存。
属性修饰符
retain:表示设置值之前先会释放旧值。
//属性声明
@property (nonatomic, retain)NSMutableArray *data;
// 属性实例化
//在事件结束时,自动释放池释放data被销毁
data = [NSMutableArray array];
data = [[NSMutableArray array] retain]; //保持
data = [[NSMutableArray alloc] init]; //保持
self.data = [NSMutableArray array];//保持
//销毁
-(void)dealloc{
[data release];
[super release];
}
属性修饰符翻译
self.property = newValue;
//assige
property = newValue;
//retain
if(property !=newValue){
[property release];
property = [newValue retain];
}
//copy
if(property!=newValue){
[property release];
[property copy];
}
自动引用计数
使用自动引用计数,系统会检测何时需要保持对象,何时需要自动释放对象。
强变量
通常,所有对象的指针变量都是强变量。
强变量赋值时,如:f1 = f2;会先对f2进行retain操作,再对f1进行release操作。
所有对象默认都是强变量,不需要声明,可使用__strong 声明
属性的默认值不是strong,是unsafe_unretained(assign)
声明强变量
@property (strong, nonatomic)NSMutableArray *array;
编译器会保证事件循环中,通过对赋值保持操作,将强变量保存下来。
弱变量
当两个对象都持有彼此的强引用时,将产生循环保持,如果对象仍然有引用,系统将不能销毁这个对象,如果两个对象都强引用到彼此,这样就不可以销毁。
当声明一个弱引用时,系统会追踪赋值给这个变量的引用。当引用对象释放时,弱变量会自动设置为nil,给nil对象发送消息不会有任何反应,所有不会导致程序崩溃。
可以使用__weak声明一个弱变量。或者为属性指定为弱引用
@property (nonatomic, weak)UIView *view;
注意:弱引用变量可以和代理进行很好的协作,创建一个代理的弱引用变量,如果代理对象被销毁,变量就会被清零。
ios4和MacOSV10.6中不支持弱变量。使用unsafe_unretained(assign)或(__unsafe_unretained)。然而当对象被销毁时,变量不再被清理。
autoreleasepool块
@autoreleasepool{}这个语句围住的范围定义了自动释放池的上下文。
如果程序中大量使用了临时变量,可以添加多个自动释放池。如:
for(int i=0; i<n; i++){
@autoreleasepool{
//与临时变量打交道。
}
}
tip:在ios应用和Cocoa应用的事件循环中。事件结束时释放自动释放池在ARC模式下系统已经帮你做好了,不需要自己做任何操作。