iOS内存管理机制

iOS文档翻译 专栏收录该内容
1 篇文章 0 订阅

在引用计数环境下的内存管理的基本模式是由定义在NSObject协议中的方法集与一个标准的方法命名规则共同规定的。NSObject类中同时也定义了一个dealloc方法,该方法会在一个对象被释放时自动地调用。本篇文章描述了在Cocoa程序中要正确管理内存,你所需要知道的所有基本规则,同时列举了一些正确用法的例子。

基本的内存管理规则

该内存管理模式基于对象的所有权。任一对象可能有一个或多个使用者。只要一个对象还有一个使用者,该对象便会继续存在。如果一个对象没有了使用者,运行系统会自动销毁它。为了搞清楚你什么时候拥有一个对象和什么时候不再拥有一个对象,Cocoa设定了以下的原则:

1.你拥有自己创建的对象的所有权

      你可以使用名字以allocnewcopymutableCopy开头的方法来创建一个对象。比如:allocnewObjectmutableCopy 

2.你可以使用retain方法拥有一个对象的所有权:

      一个接收的对象通常要保证在接收该对象的方法体内有效,且方法体也可以安全地返回一个对象给它的调用者。你在两种情况下使用retain方法:(1)在访问方法或init方法的实现中,为了获得你想要存储为属性值的对象的所有权;(2)防止对象被一些其它操作意外销毁(见Avoid Causing Deallocation of Objects You’re Using)。 

3.当你不再需要一个你所拥有的对象时,你必须放弃对象的所有权:

      你可以通过给对象发送一个releaseautorelease消息来放弃对该对象的所有权。因此,在Cocoa术语中,放弃一个对象的所有权通常被称为释放一个对象。 

4.你不可以释放一个你并不拥有的对象的所有权:

      明确地规定,这只是上述政策规则的必然推论。

一个简单的例子

       为了说明这个规则,请考虑下面的代码片段:

{

    Person *aPerson = [[Person alloc] init];

    // ...

    NSString *name = aPerson.fullName;

    // ...

    [aPerson release];

}

使用alloc方法创建了Person对象(即aPerson),因此随后当不再需要它时,它被发送了一个release消息。变量name没有被任何拥有的方法取回,因此它没有被发送release消息。请注意,例子中使用了release而不是autorelease

 

使用autorelease发送一个延时的release

在你需要发送一个延迟的release消息时,你可以使用autorelease ——典型的情况是,当你需要从一个方法中返回一个对象。例如,你可以像下面这样来实现fullName方法:

 (NSString *) fullName

{

    NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@",self.firstName, self.lastName] autorelease];

    return string;

}

 

你拥有由alloc方法返回的string对象的所有权。为了遵守内存管理规则,你必须在失去string的引用前释放它的所有权。然而,如果你使用releasestring对象会在被返回前就被销毁(该方法将会返回一个无效的对象)。使用autorelease,你表明了你想释放所有权,但是你允许方法的调用者在string对象被销毁前使用返回的string对象。

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

- (NSString *)fullName

 {

    NSString *string = [NSString stringWithFormat:@"%@ %@",

                                 self.firstName, self.lastName];

    return string;

}

根据基本规则,你并不拥有由stringWithFormat:方法返回的对象string,因此,你可以安全地从方法体中返回string对象。

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

- (NSString *)fullName

 {

    NSString *string = [[NSString alloc] initWithFormat:@"%@ %@",

                                         self.firstName, self.lastName];

    return string;

}

根据命名规则,没有哪一处指明fullName方法的调用者拥有返回的string。因此,调用者没有理由去释放要返回的string,该string对象将会产生内存泄漏。

你并不拥有通过引用返回的对象的所有权:

Cocoa中,一些方法明确说明了要通过引用来返回一个对象(也就是说,他们有一个类型为ClassName ** id *的变量)。 一个常见的​​模式是使用NSError对象,其中包含有关错误的信息,像initWithContentsOfURL:options:error: (NSData)方法和initWithContentsOfFile:encoding:error: (NSString)方法中说明的。

根据前面已经描述的,同样的规则被应用在这些例子中。当你调用这些方法(指的是上面的两个)中的任意一个,你没有创建NSError对象,你并不拥有它。因此,你不必要释放它,如同下面这个例子中说明的:

NSString  *fileName =@"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方法,它会在一个对象没有使用者时被自动调用,该对象的内存会被回收——Cocoa术语中,是freed(被释放)或deallocated(被重新分配)。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

重要提示:

1.        绝不要去直接调用另一个对象的dealloc方法;

你必须在自定义的实现方法的结尾处调用父类的实现方法(dealloc方法)。

2.        你不应该把系统资源的管理绑定在对象的生存期上;见Don’t Use dealloc to Manage Scarce Resources

当应用程序终止时,对象可能不被发送dealloc消息。因为应用进程的内存会在退出时被自动清理。让操作系统去清理资源而不是调用所有的内存管理方法是一种更有效简单的方法。

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

Core Foundation框架采用相似的内存管理机制。然而,CocoaCore Foundation的命名习惯是不同的。特别地,Core FoundationCreate Rule并不适用于返回Objective-C对象的方法。例如,在下面的代码片段中,你没有责任去释放myInstance实例的所有权。

MyClass *myInstance = [MyClass createInstance];

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值