赞
踩
Objective-C的内存管理要比Java复杂多了,很有挑战性,它提供了三种方法:
- Explicit
有可以通过alloc, copy等方法为对象分配内存,dealloc销毁已分配的内存。这种方法你可以对内存管理有完全的控制力,高性能但是出错的可能也大。
- Retain count
利用OpenStep的retain/release机制,同时使用autorelease pools来提供一定程度的自动化内存管理,这种方法提供了比较好的对内存管理的控制,但是需要仔细的遵循一些简单的规则,这种方法效率也很高。
- Garbage collection
类似于Java的内存回收机制,但是比起Java来就差远了,还有一定使用限制,iOS上是不支持的,所以暂时先不研究了。
话说虽然是三个方法,但是主要还是使用第二种。建议使用NSObject.h里面的一些标准的macro来包装etain/release/autorelease机制。
标准的OpenStep系统利用retain count来进行内存管理,当一个对象被创建时,它的retain count是1. 当对象被retain时,这个retain count增加,当对象被release时,这个retain count减少,当retain count减少到零时,对象就被销毁了。
Coin*c = [[Coin alloc] initWithValue: 10];
// Put coin in pouch,
[c retain];// Calls 'retain' method (retain count now 2)
// Remove coin from pouch
[c release];// Calls 'release' method (retain count now 1)
// Drop in bottomless well
[c release];// Calls 'release' ... (retain count 0) then 'dealloc'
如果一个代码块中一个对象被创建了,它就有义务release掉这个对象,如果一个代码块只是简单使用某个对象,那它就没义务release这个对象。简单的说,总的retain数应该等于总的releasee数。
NSString *msg = [[NSString alloc] initWithString: @"Test message."];
NSLog(msg);
// we created msg with alloc -- release it
[msg release];
Retain和release必须被用来操作对象的实例:
- (void)setFoo:(FooClass *newFoo)
{
// first, assert reference to newFoo 保证这期间,该对象不被销毁
[newFoo retain];
// now release reference to foo (do second since maybe newFoo == foo)
[foo release];
// finally make the new assignment; old foo was released and may
// be destroyed if retain count has reached 0
foo = newFoo;
}
因为有retain/release机制, 你甚至可以在类中使用setter方法:
- (void)resetFoo
{
FooClass *foo = [[FooClass alloc] init];
[self setFoo: foo];
// since -setFoo just retained, we can and should
// undo the retain done by alloc
[foo release];
}
例外
有些情况下前面说的关于在代码块中成对使用retain和release的规则并不适用,比方说实现一个container类retain了所有加入到这个container中的对象,同时在这个container被销毁时(在某个方法中),销毁所有它包含的对象。总的来说你要注意成对使用retain和release。
Autorelease Pools
有一种情况,当一个对象被转移给另一个对象时,你不想在转移的代码里加retain,但是你又不想让这个对象在完成转移前被销毁掉。OpenStep/GNUstep的解决方案是在这种情况下使用autorelease pool. 一个autorelease pool是一种特殊的机制,会retain对象一定的时间,当然这个时间肯定足够完成对象转移的。实现方法是调用autorelease而不是release. Autorelease首先会把这个对象放到活动的autorelease pool中(这里retain这个对象),然后再给这个对象发一个release消息,等过一段时间之后,autorelease pool会发第二个release消息
- (NSString *) getStatus
{
NSString *status =
[[NSString alloc] initWithFormat: "Count is %d", [self getCount]];
// set to be released sometime in the future
[status autorelease];
return status;
}
如果只在本地使用的话,任何调用-getStatus的代码都可以不需要retain这个方法的返回对象。当然,如果返回需要被保存并且以后使用的话,那就需要retain了。
...
NSString *status = [foo getStatus];
// 'status' is still being retained by the autorelease pool
NSLog(status);
return;
// status will be released automatically later
...
currentStatus = [foo getStatus];
// currentStatus is an instance variable; we do not want its value
// to be destroyed when the autorelease pool cleans up, so we
// retain it ourselves
[currentStatus retain];
Pool Management
一个autorelease pool在GNUstep GUI类中会被自动创建,然而如果你只是使用GNUstep Base类的话你就需要自己来创建了。
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
一旦一个pool被创建之后,所有的autorelease会自动找到它。如果需要关掉这个pool并release它包含的所有的对象的话,只需要release掉pool就可以。
有可能你还会需要创建多个additional pool,那样的话autorelease会找最近创建的进行保存。
autorelease要比release慢很多,所以只在需要用的时候使用它。
避免循环Retain
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。