您现在的位置是:首页 >技术交流 >iOS内存管理网站首页技术交流

iOS内存管理

漓江塔塔主 2023-06-06 20:00:03
简介iOS内存管理

内存管理

在引用计数环境中用于内存管理的基本模型由NSobject协议中定义的方法和标准方法命名约定的组合提供,NSObject类还定义了一个方法dealloc,该方法在对象被取消分配时自动调用
#本文介绍了在cocoa程序中正确管理内存需要知道的所有基本规则,并提供了一些正确的使用示例

基本内存管理规则

内存管理模型基于对象的所有权(是否持有),任何对象都可以有一个或者多个所有者,只要一个实例存在至少一个持有者,那么他就不会被自动销毁,如果没有,则在运行时系统会自动销毁它,为了确保清楚您何时拥有对象,何时不拥有对象,cocoa设置了以下策略

  • 你拥有你所创建的任何对象
    使用"alloc"“new”“copy”"mutableCopy"开头的方法来创建对象

  • 使用retain来获得对象的所有权
    接收的对象通常保证在接收的方法中保持有效,该方法也可以安全地将对象返回到其调用者,两种情况下使用retain「在实现setter/getter方法或者init方法的时候,获得存储为属性的对象的所有权」,「防止对象作为其他操作的副作用而失效」

  • 当你不需要时,你必须放弃该实例对象的所有权
    通过向对象发送release消息或者autorelease消息来放弃持有, 在cocoa框架下,放弃对象的所有权通常被称为“释放”对象

  • 无法释放一个你未持有的对象的所有权
    以上规则的推论

简单例子

{

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

    // ...

    NSString *name = aPerson.fullName;

    // ...

    [aPerson release];

}

person对象是由alloc创建的,当他不在被需要的时候,要发送一个释放消息
Person对象的name没有用任何拥有的方法检索到,所以它不发送释放消息。注意,尽管如此,这个例子使用release而不是autorelease。

使用autorelease发送延迟释放

当需要发送延迟release消息时,可以使用autorelease——通常是在从方法返回对象时。例如,您可以像这样实现fullName方法:

- (NSString *)fullName {

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

}

通过alloc来持有该对象,为了遵循内存管理规则,你必须在失去这个字符串的引用之前释放它,但是如果你使用了release该字符串将在返回之前(引用之前)被释放,「将返回一个无效对象」,使用autorelease表示你要释放持有该对象,但您允许方法的调用者在释放之前使用该返回的字符串
还可以这样 实现该方法

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

按照基本规则,你不拥有stringWithFormat:返回的字符串,因此你可以安全的从方法返回字符串。(没有使用alloc方法持有该对象)
相比之下一下的实现是错误的

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

根据命名规则,并没有表明fullName方法的调用者持有返回的字符串。因此调用者没有理由释放返回的字符串,并且字符串将会因此被泄漏(OOM)

你不会持有引用返回的对象

cocoa中的一些方法,明确指出了对象是由引用返回的(那是因为他们携带了一个ClassName或者id类型的参数)常见的模式是如果发生错误,使用包含错误信息的NSError对象,如NSData的initWithContentsOfURL:options:error:方法和NSString的initWithContentsOfFile:encoding:error:
方法所示。
在这些情况下,同样的规则应用已经被描述过了。当你调用这些方法时,你不创建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,当一个对象没有拥有者并且它的内存被回收(在Cocoa术语中叫“freed” 或者 “deallocated”),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

不要直接调用另一个对象的dealloc方法,你必须在你实现的结尾调用父类的实现你不应该将系统资源的管理和对象的生命周期绑定在一起;参见Don’t Use dealloc to Manage Scarce Resources
当一个应用程序终止时,对象可能不会发送dealloc消息。因为进程的内存在退出时会自动清除,允许操作系统清除资源比调用所有的内存管理方法更有效

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

Core Foundation对象有类似的内存管理规则(请参阅_Core Foundation的内存管理编程指南_)。然而,Cocoa和Core Foundation的命名惯例是不同的。特别是,Core Foundation的创建规则(请参阅创建规则)不适用于返回Objective-C对象的方法。例如,在以下代码片段中,您不负责释放myInstance的所有权:
MyClass *myInstance = [MyClass createInstance];

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。