引用计数
Cocoa 采用引用计数技术管理对象。
- 当使用 alloc、new 方法或通过 copy 消息(生成接收对象的一个副本)创建一个对象时,对象的保留计数器值被设置为 1 。
- 要增加对象的保留计数器值,可以给对象发送一条 retain 消息。
- 要减少对象的保留计数器值,可以给对象发送一条 release 消息。
- 要获得保留计数器的当前值,可以发送 retainCount 消息。
1 2 3
| - (id) retain; - (void) release; - (unsigned) retainCount;
|
当一个对象因保留计数器归 0 而即将被销毁时,Objective-C 自动向对象发送一条 dealloc 消息。你可以在自己的对象中重写 dealloc 方法。可以通过这种方法释放已经分配的全部相关资源。一定不要直接调用 dealloc 方法。可以利用 Objective-C 在需要销毁对象时调用 dealloc 方法。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| @interface RetainTracker : NSObject @end // RetainTracker @implementation RetainTracker - (id) init { if (self = [super init]) { NSLog (@"init: Retain count of %d.", [self retainCount]); } return (self); } // init - (void) dealloc { NSLog (@"dealloc called. Bye Bye."); [super dealloc]; } // dealloc @end // RetainTracker int main (int argc, const char *argv[]) { RetainTracker *tracker = [RetainTracker new]; // count: 1 [tracker retain]; // count: 2 NSLog (@"%d", [tracker retainCount]); [tracker retain]; // count: 3 NSLog (@"%d", [tracker retainCount); [tracker release]; // count: 2 NSLog (@"%d", [tracker retainCount); [tracker release]; // count: 1 NSLog (@"%d", [tracker retainCount); [tracker retain]; // count: 2 NSLog (@"%d", [tracker retainCount); [tracker release]; // count: 1 NSLog (@"%d", [tracker retainCount); [tracker release]; // count: 0, dealloc it return (0); } // main
|
对象所有权
-
如果某个实体拥有一个对象,则该实体要负责确保对其拥有的对象进行清理。
-
这个实体可以是另一个对象,或者一个函数。例如,在 Car 类中, car 对象拥有其指向的 engine 和 tire 对象。又比如,main() 函数创建了一个新的 car 对象,因此称 main() 函数拥有 car 对象。
-
多个实体可以同时拥有同一个特定对象。此时要格外注意考虑对象的所有权关系。
自动释放池
Cocoa 中有一个自动释放池(autorelease pool)的概念。顾名思义,它是一个存放实体的池(集合),这些实体可能是对象,能够被自动释放。
NSObject 类提供了一个 autorelease 方法:
当给一个对象发送 autorelease 消息时,实际上是将该对象添加到 NSAutoreleasePool 中。当自动释放池被销毁时,会向该池中的所有对象发送 release 消息。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| int main (int argc, const char *argv[]) { NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init]; RetainTracker *tracker; tracker = [RetainTracker new]; // count: 1 [tracker retain]; // count: 2 [tracker autorelease]; // count: still 2 [tracker release]; // count: 1 NSLog (@"releasing pool"); [pool release]; // gets nuked, sends release to tracker return (0); } // main
|
内存管理规则
- 如果使用 new、 alloc 或 copy 操作获得一个对象,则该对象的保留计数器值为 1 。当不再使用该对象时,你要负责向该对象发送一条 release 或 autorelease 消息。这样,该对象在其使用寿命结束时被销毁。
- 如果通过任何其他方法获得一个对象时,则假设该对象的保留计数器值为 1 ,而且已经被设置为自动释放。你不需要执行任何操作来确保该对象被清理。
- 如果保留了某个对象,则必须保持 retain 方法和 release 方法的使用次数相等。
垃圾回收
Objective-C 2.0 引入了垃圾回收机制。对于已经创建和使用的对象,当你忘记清理它们时,系统会自动识别哪些对象仍在使用,哪些对象可以回收。启用垃圾回收非常简单,只不过这是一种可选择启用的功能。只需转到项目信息窗口的 Build 选项卡,然后选择 Required [-fobjc-gc-only] 选项即可。
启用垃圾回收以后,通常的内存管理命令全都变成了空操作指令,不执行任何操作。
垃圾回收器定期检查变量和对象以及它们之间的指针,当发现没有任何变量指向某个对象时,就将该对象视为应该被丢弃的垃圾。因此,如果你在一个实例变量中指向某个对象,一定要在某个时候将该实例变量赋值为 nil ,以取消对该对象的引用并使垃圾回收器知道该对象可以被清理了。
注意:如果开发 iPhone 软件,则不能使用垃圾回收。实际上,苹果公司建议 iPhone 开发者不要在自己的代码中使用 autorelease 方法,同时还要避免使用创建自动释放对象的便利函数。