注:本章对初学者比较晦涩,建议参考或直接阅读英文原本来理解。
1.对象生命周期 对象的生命周期包括诞生(通过alloc或new方法实现)、生存(接收消息和执行操作)、交友(借助方法的组合和参数)、释放(当它们的生命结束时最终死去)。当对象的生命周期结束时,它们的原材料(内存)将被回收以供新的对象使用。
引用计数(reference counting):每个对象有一个与之相关联的整数,称做它的引用计数器或保留计数器。当某段代码需要访问一个对象时,该代码将该对象的保留计数器值加1,表示“我要访问该对象”。当这段代码结束对象访问时,将对象的保留计数器值减1,表示它不再访问该对象。当保留计数器值为0时,表示不再有代码访问该对象了,因此对象将被销毁,其占用的内存被系统回收以便重用。
当使用alloc、new或copy(生成接收对象的一个副本)创建一个对象时,对象的保留计数器值被设置成1.要增加对象的保留计数器值,可以给对象发送一条retain消息,要减少对象的保留计数器值,可以给对象发送一条release消息。
当一个对象因其保留计数器归0而将被销毁时,Objective-C自动向对象发送一条dealloc消息。你可以在自己的对象中重写dealloc方法。可以通过这种方式释放已经分配的全部相关资源。一定不要直接调用dealloc方法。要获得保留计数器的当前值,可以发送retainCount消息。签名如下:
- (id) retain; //申请 - (void) release; //释放 - (unsigned) retainCount; //当前计数器值
例如:[[car retain] setTire: tire atIndex:2]; 表示要求car对象将其保留计数器值加1并执行setTire操作。 Example:
1 // 2 // Main.m 3 // RetainCount1 4 // 内存管理练习1 5 // 6 // Created by Elf Sundae on 10/23/10. 7 // Copyright 2010 Elf.Sundae(at)Gmail.com. All rights reserved. 8 // 9 10 #import <Cocoa/Cocoa.h> 11 12 @interface RetainTracker : NSObject 13 14 @end 15 16 @implementation RetainTracker 17 18 - (id) init 19 { 20 if (self = [super init]) 21 { 22 NSLog(@"init: Retain count of %d.",[self retainCount]); 23 } 24 return self; 25 } 26 27 - (void) dealloc 28 { 29 NSLog(@"dealloc called.Bye Bye."); 30 [super dealloc]; 31 } 32 33 @end 34 35 36 37 int main (int argc, const char * argv[]) 38 { 39 40 41 RetainTracker *tracker = [RetainTracker new]; 42 43 [tracker retain]; 44 NSLog(@"%d",[tracker retainCount]); 45 46 [tracker retain]; 47 NSLog(@"%d",[tracker retainCount]); 48 49 [tracker release]; 50 NSLog(@"%d",[tracker retainCount]); 51 52 53 [tracker release]; 54 NSLog(@"%d",[tracker retainCount]); 55 56 [tracker retain]; 57 NSLog(@"%d",[tracker retainCount]); 58 59 [tracker release]; 60 NSLog(@"%d",[tracker retainCount]); 61 62 [tracker release]; 63 64 65 return 0; 66 } 67
输出:
init: Retain count of 1. 2 3 2 1 2 1 dealloc called.Bye Bye.
2.对象所有权(object ownership): 如果一个对象具有指向其他对象的实例变量,则称该对象拥有这些对象。这意味着该实体要负责确保对其拥有的对象进行清理。 当多个实体拥有某个特定对象时,对象的所有权关系就更复杂了,这也是保留计数器值可能大于1的原因。在上面的RetainCount1例子中,main()函数拥有RetainTracker类的对象,因此main()要负责清理该类的对象。 回忆一下在OOP基础章节里Car的engine setter方法:
- (void) setEngine: (Engine *) newEngine;
以及如何在main()函数中调用该方法:
Engine *engine = [Engine new]; [car setEngine: engine];
现在哪个实体拥有engine对象?是main()函数还是Car类?
下面是编写setEngine的一种更好的方法:
1 - (void) setEngine: (Engine *) newEngine 2 { 3 [newEngine retain]; 4 [engine release]; 5 engine = newEngine; 6 } // setEngine
在访问方法中,如果先保留新对象,然后再释放旧对象,这不会出问题。 In your accessors, if you retain the new object before you release the old object, you’ll be safe.
3.自动释放(Autorelease) 自动释放池(autorelease pool),它是一个存放实体的池(集合),这些实体可能是对象,能够被自动释放。 NSObject类提供了一个autorelease方法:
该方法预先设定了一条在将来某个时间发送的release消息,其返回值是接收消息的对象。当给一个对象发送autorelease消息时,实际上是将该对象添加到NSAutoreleasePool中。当自动释放池被销毁时,会向该池中的所有对象发送release消息。
1- (NSString *) description 2{ 3 NSString *description; 4 description = [[NSString alloc] 5 initWithFormat: @"I am %d years old", 4]; 6 return ([description autorelease]); 7} // description
自动释放池的销毁时间: 在使用Foundation库工具中,创建和销毁自动释放池的方法非常明确:
NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init]; … [pool release];
创建一个自动释放池时,该池自动成为活动的池。释放该池时,其保留计数器值归0,然后该池被销毁。在销毁过程中,该池释放其包含的所有对象。 当时用AppKit时,Cocoa定期自动为你创建和销毁自动释放池。通常是在程序处理完当前事件(如鼠标单击或按键)以后执行这些操作。你可以使用任意多的自动释放对象,当不再使用它们时,自动释放池将自动为你清理这些对象。 说明:在Xcode自动生成的代码中使用了另一种销毁自动释放池中对象的方式:-drain方法,该方法只是清空自动释放池而不销毁它。-drain方法只适用于Mac OS X 10.4(Tiger)及更高版本。
自动释放池的工作过程: 示例:RetainCount2
OBJECTIVE-C CODE :RetainCount2
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
//
// Main.m
// RetainCount2
// 内存管理练习2: 使用自动释放池
//
// Created by Elf Sundae on 10/25/10.
// Copyright 2010 Elf.Sundae(at)Gmail.com. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface RetainTracker : NSObject
@end
@implementation RetainTracker
- (id) init
{
if (self = [super init])
{
NSLog(@"init: Retain count of %d.",[self retainCount]);
}
return self;
}
- (void) dealloc
{
NSLog(@"dealloc called.Bye Bye.");
[super dealloc];
}
@end
int main (int argc, const char * argv[])
{
// 创建一个自动释放池
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
// 创建(new)一个RetainTracket对象
RetainTracker *tracker = [RetainTracker new]; // count:1
NSLog(@"%d",[tracker retainCount]);
// 处于演示目的,retain一个trancker
[tracker retain]; // count:2
NSLog(@"%d",[tracker retainCount]);
// 向对象发送autorelease消息,将该对象添加到自动释放池pool中
[tracker autorelease]; // count: still 2
NSLog(@"%d",[tracker retainCount]);
// release该对象以抵消上面的 retain
[tracker release]; //count: 1
NSLog(@"%d",[tracker retainCount]);
NSLog(@"releaseing pool");
[pool release];
return 0;
}
|
|
请发表评论