内存管理策略

在引用计数环境中用于内存管理的基本模型由 NSObject 协议中定义的方法和标准方法命名约定的组合提供。NSObject 类还定义了一个方法 dealloc,它在释放对象时自动调用。

基本内存管理规则

内存管理模型基于对象所有权。任何对象都可能有一个或多个所有者。只要一个对象至少有一个所有者,它就会继续存在。如果一个对象没有所有者,则运行时系统将自动销毁它。

Cocoa 设置了以下策略:

  • 你拥有你创建的任何对象

    你可以使用名称以 “alloc”,“new”,“copy” 或 “mutableCopy” 开头的方法创建对象。

  • 你可以使用 retain 取得对象的所有权

    接收到的对象通常保证在接收到的方法内保持有效,并且该方法还可以安全地将该对象返回给其调用者。在两种情况下使用 retain:(1)在访问器方法或 init 方法的实现中,将要存储的对象的所有权作为属性值;(2)防止对象作为其他操作的副作用而失效。

  • 当你不再需要它时,你必须放弃你拥有的对象的所有权

你通过向对象发送 release 消息或 autorelease 消息来放弃对象的所有权。在 Cocoa 术语中,放弃对象的所有权通常被称为“释放”对象。

  • 你不能释放你不拥有的对象
一个简单的例子
{
    Person *aPerson = [[Person alloc] init];
    // ...
    NSString *name = aPerson.fullName;
    // ...
    [aPerson release];
}

Person 对象是使用 alloc 方法创建的,因此随后会在不再需要时发送释放消息。person 的 name 不是使用任何拥有方法获取的,因此不会发送释放消息。但请注意,该示例使用 release 而不是 autorelease。

使用 autorelease 延迟释放

当需要发延迟释放消息时,使用 autorelease,通常在从方法返回对象时。

- (NSString *)fullName {
    NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@",
                                          self.firstName, self.lastName] autorelease];
    return string;
}

你拥有由 alloc 返回的字符串。要遵守内存管理规则,必须先放弃字符串的所有权,然后再丢失对该字符串的引用。如果使用 release,字符串将在返回之前释放(该方法会返回一个无效的对象)。使用 autorelease,表示你想放弃所有权,但是你允许方法的调用方在释放之前使用返回的字符串。

你也可以像这样实现 fullName 方法:

- (NSString *)fullName {
    NSString *string = [NSString stringWithFormat:@"%@ %@",
                                 self.firstName, self.lastName];
    return string;
}

遵循基本规则,您不拥有stringWithFormat返回的字符串,因此您可以安全地从方法返回字符串。

相反,下面的实现是错误的:

- (NSString *)fullName {
    NSString *string = [[NSString alloc] initWithFormat:@"%@ %@",
                                         self.firstName, self.lastName];
    return string;
}

根据命名约定,没有什么可以表示 fullName 方法的调用者拥有返回的字符串。因此调用者没有理由释放返回的字符串,因此会被泄漏。

你不拥有引用返回的对象

Cocoa 中的一些方法指定一个对象是通过引用返回的。一个常见的模式是使用包含错误信息的NSError对象(如果发生错误),如initWithContentsOfURL:options:error:(NSData)initWithContentsOfFile:encoding:error:(NSString) 所示。

在这些情况下,适用的规则与已经描述的相同。当你调用任何这些方法时,你不会创建NSError对象,所以你不拥有它。因此不需要释放它,如下例所示:

NSString *fileName = <#Get a file name#>;
NSError *error;
NSString *string = [[NSString alloc] initWithContentsOfFile:fileName
                        encoding:NSUTF8StringEncoding error:&error];
if (string == nil) {
    // Deal with error...
}
// ...
[string release];

实现 dealloc 来放弃对象的所有权

NSObject 类定义了一个方法 dealloc,当对象没有所有者并且其内存被回收(被释放)时它会自动调用。dealloc方法的作用是释放对象自己的内存,并处理它拥有的任何资源,包括任何对象实例变量的所有权。

以下示例说明了如何为 Person 类实现 dealloc 方法:

@interface Person : NSObject
@property (retain) NSString *firstName;
@property (retain) NSString *lastName;
@property (assign, readonly) NSString *fullName;
@end

@implementation Person
// ...
- (void)dealloc
    [_firstName release];
    [_lastName release];
    [super dealloc];
}
@end

Core Foundation 使用类似但不同的规则

Core Foundation 对象有类似的内存管理规则。然而,Cocoa 和 Core Foundation 的命名约定是不同的。特别是,Core Foundation的创建规则不适用于返回 Objective-C 对象的方法。例如,在下面的代码片段中,您不负责放弃 myInstance 的所有权:

MyClass *myInstance = [MyClass createInstance];
参考资料
  1. Memory Management Policy

results matching ""

    No results matching ""