[IOS]关于Obj-C内存管理的规则

Objective-C 2.0增加了一些新的东西,包括属性和垃圾回收。那么,我们在学习Objective-C 2.0之前,最好应该先了解,从前是什么样的,为什么Objective-C 2.0要增加这些支持。

这一切都跟Cocoa内存的管理规则有关系,我们知道,Objective-C中所有变量都定义为指针。指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址,如果使用不当,就会出错或者造成内存的泄露。要了解这些,就需要看看其内存管理的规则到底是什么样的。

这篇文章也应该做为苹果开发工具中提供的性能调试工具Instruments使用前必读知识进行阅读。Cocoa China将在稍后提供Instruments工具的使用方法,以及Objective-C 2.0的详细介绍。

要知道,如果你使用Objective-C 2.0,那么本文描述的大部分工作你都不需要自己去处理了。但是这并不意味着你可以不了解它,相反,只有你对内存管理规则更加了解,你才能更好地使用Objective-C 2.0带来的便利。

 

本文原文作者是Mmalcolm Crawford,原文地址 这篇文章翻译起来比较晦涩,希望您能看得懂。

 

当Cocoa新手在进行内存管理时,他们看上去总是把事情变得更为复杂。遵循几个简单的规则就可以把生活变得更简单。而不遵循这些规则,他们几乎一定会造成诸如内存泄露或者将消息发送给释放掉的对象而出现的的运行错误。

 

Cocoa不使用垃圾回收(当然,Objective-C 2.0之后开始就使用了),你必须通过计算reference的数量进行自己的内存管理,使用-retain, -release和-autorelease。

 

方法描述

-retain

将一个对象的reference数量增加1。

-release

将一个对象的reference数量减少1。

-autorelease

在未来某些时候将reference数量减少1.

-alloc

为一个对象分配内存,并设置保留值数量(retain count)为1。

-copy

复制一个对象,并将其做为返回值。同时设置保留值数量(retain count)为1。

保留值数量规则

1 在一定的代码段中,使用-copy,-alloc和-retain的次数应该和-release,-autorelease保持一致。

2 使用便利构造方法创建的对象(比如NSString的stringWithString)可以被认为会被自动释放。(autoreleased)

3 在使用你自己的参数实例时,需要实现-dealloc方法来释放。

例子

-alloc / -release

 

 

- (void)printHello 

{

NSString *string;

string = [[NSString alloc] initWithString:@"Hello"];

NSLog(string);

// 我们用 alloc 创建了NSString,那么需要释放它

[string release];

}

 

便利构造方法

 

 

- (void)printHello 

{

NSString *string;

string = [NSString stringWithFormat:@"Hello"];

NSLog(string);

// 我们用便利构造方法创建的NSString

//我们可以认为它会被自动释放

}

 

永远使用存取方法

虽然有时候你可能会认为这很麻烦,但是如果你始终使用了存取方法,造成内存管理问题的麻烦将会降低很多。

如果你在代码实例的参数中频繁使用-retain和-release,几乎可以肯定你做了错误的事情。

例子

假设我们希望设置一个Counter对象的数量值。

 

@interface Counter : NSObject

{

NSNumber *count;

}

 

为了获取和设置count值,我们定义两个存取方法:

 

- (NSNumber *)count 

{

return count;

// 无需retain或者release,

// 仅仅传递数值

}

 

 

- (void)setCount:(NSNumber *)newCount 

{

 

// newCount值会被自动释放,那么我们希望保留这个newCount

// 所以需要在这里retain。

[newCount retain];

 

// 由于我们在这个方法中仅仅改变了计算数量的对象,我们可以在这里先释放它。因为[nil release]在objective-c中也是允许的,所以即使count值没有被指定,也可以这样调用。

//我们必须在[newCount retain]之后再释放count,因为有可能这两个对象的指针是同一个。我们不希望不小心释放它。

[count release];

 

// 重新指定

count = newCount;

}

 

命名约定

注意存取方法的命名约定遵循一个模式: -参数名 和 -set参数名。

遵循这一约定,会使你的代码可读性更强,而且,更重要地是你可以在后面使用key-value编码。(参阅NSKeyValueCoding协议)。

由于我们有一个对象实例参数,我们必须实现一个释放方法:

 

- (void)dealloc 

{

[self setCount:nil];

[super dealloc];

}

 

假设我们希望实现一个方法重置计数器,我们会有很多选择。在最开始,我们使用了一个 便利构造方法,所以我们假设新的数值是自动释放的。我们不需要发送任何retain或者release消息。

 

- (void)reset 

{

NSNumber *zero = [NSNumber numberWithInt:0];

[self setCount:zero];

}

 

然而,如果我们使用-alloc方法建立的NSNumber实例,那我们必须同时使用一个-release。

 

 

- (void)reset 

{

NSNumber *zero = [[NSNumber alloc] initWithInt:0];

[self setCount:zero];

[zero release];

}

常见错误

在简单的情况下,以下代码几乎一定可以正常运行,但是由于可能没有使用存取方法,下面的代码在某些情况下几乎一定会出问题。

 

错误-没有使用存取方法

 

- (void)reset 

{

NSNumber *zero = [[NSNumber alloc] initWithInt:0];

[count release]

count = zero;

}

 

错误-实例泄露

 

 

- (void)reset 

{

NSNumber *zero = [[NSNumber alloc] initWithInt:0];

[self setCount:zero];

}

 

新建的NSNumber数值数量是1(通过alloc),而我们在这个方法里没有发出-release消息。那么这个NSNumber就永远不会被释放了,这样就会造成内存泄露。

错误-对已经释放的实例发送-release消息

 

 

- (void)reset 

{

NSNumber *zero = [NSNumber numberWithInt:0];

[self setCount:zero];

[zero release];

}

 

你随后在存取count的时候在这里就会出错。这个简便构造方法会返回一个自动释放的对象,你无需发送其他释放消息。

这样写代码意味着,由于对象已经被自动释放,那么当你释放时,retain count将被减至0,对象已经不存在了。当你下次希望获取count值时,你的消息会发到一个不存在的对象(通常这样你会得到一个SIGBUS 10的错误提示)。

经常造成混淆的情况

数组和其他集合类

当对象被加入到数组、字典或者集合中,集合类会将其保留。当集合被释放的同时,对象也会收到一个释放消息。如果你希望写一个建立数字数组的例子,你可能会这么写:

 

NSMutableArray *array;

int i;

// …

for (i = 0; i < 10; i++) 

{

NSNumber *n = [NSNumber numberWithInt: i];

[array addObject: n];

}

 

在这个例子里,你无需保留新建的数值,因为数组会帮你保留。

 

NSMutableArray *array;

int i;

// …

for (i = 0; i < 10; i++) 

{

NSNumber *n = [[NSNumber alloc] initWithInt: i];

[array addObject: n];

[n release];

}

本例中,在for循环里你需要给n发送一个-release消息,因为你需要始终在-alloc之后将n的数量保持为1。这么做的原因是当其通过-addObject:方法被添加至数组中时,数组已经将其保存起来。即使你释放了n,但是这个数字由于已经保存在数组里,所以不会被释放。

为了了解这些,假设你自己就是编写数组类的人。你不希望接收的对象未经你同意就消失,所以你会在对象传递进来时,对其发送一个-retain消息。如果他们被删除,你同时也要对应地发送一个-release消息。在你自己-dealloc时,你也要给你收到的所有对象发送一个-release。

 

原文地址:http://www.cocoachina.com/b/?p=110

时间: 2025-01-21 10:28:33

[IOS]关于Obj-C内存管理的规则的相关文章

iOS学习笔记之内存管理及@property

iOS5之后苹果公司引入了ARC机制,大大方便了ios开发者对内存的管理机制.在iphone 4出世的时候为什么ios在512M的内存中可以运行很大的游戏,保持畅快流畅的状态.得益于ios非常好的内存处理机制.       在我们现在创建项目的时候,默认会直接引入ARC机制,我们可以关闭ARC机制:在输入框中输入long点击搜索按钮,如图:          接下来即可进行老版本的内存操作了. 在老版本中,内存操作采用了引用计数(retainCount)alloc retain(+1)relea

iOS/OS X内存管理(一):基本概念与原理

在Objective-C的内存管理中,其实就是引用计数(reference count)的管理.内存管理就是在程序需要时程序员分配一段内存空间,而当使用完之后将它释放.如果程序员对内存资源使用不当,有时不仅会造成内存资源浪费,甚至会导致程序crach.我们将会从引用计数和内存管理规则等基本概念开始,然后讲述有哪些内存管理方法,最后注意有哪些常见内存问题.    memory management from apple document  基本概念 引用计数(Reference Count) 为了

理解iOS的内存管理

远古时代的故事 那些经历过手工管理内存(MRC)时代的人们,一定对 iOS 开发中的内存管理记忆犹新.那个时候大约是 2010 年,国内 iOS 开发刚刚兴起,tinyfool 大叔的大名已经如雷贯耳,而我还是一个默默无闻的刚毕业的小子.那个时候的 iOS 开发过程是这样的: 我们先写好一段 iOS 的代码,然后屏住呼吸,开始运行它,不出所料,它崩溃了.在 MRC 时代,即使是最牛逼的 iOS 开发者,也不能保证一次性就写出完美的内存管理代码.于是,我们开始一步一步调试,试着打印出每个怀疑对象的

iOS ARC 内存管理要点

前言 在讨论 ARC 之前,我们需要知道 Objective-C 采用的是引用计数式的内存管理方式,这一方式的特点是: 自己生成的对象自己持有.比如:NSObject * __strong object = [NSObject alloc] init];. 非自己生成的对象自己也能持有.比如:NSMutableArray * __strong array = [NSMutableArray array];. 自己持有的对象不再需要时释放. 非自己持有的对象自己无法释放. 而 ARC 则是帮助我们

详解iOS应用开发中的ARC内存管理方式_IOS

提示:本文中所说的"实例变量"即是"成员变量","局部变量"即是"本地变量" 零.简介ARC是自iOS 5之后增加的新特性,完全消除了手动管理内存的烦琐,编译器会自动在适当的地方插入适当的retain.release.autorelease语句.你不再需要担心内存管理,因为编译器为你处理了一切 注意:ARC 是编译器特性,而不是 iOS 运行时特性(除了weak指针系统),它也不是类似于其它语言中的垃圾收集器.因此 ARC 和

iOS 进阶—— iOS内存管理

1 似乎每个人在学习 iOS 过程中都考虑过的问题 alloc retain release delloc 做了什么? autoreleasepool 是怎样实现的? __unsafe_unretained 是什么? Block 是怎样实现的 什么时候会引起循环引用,什么时候不会引起循环引用? 所以我将在本篇博文中详细的从 ARC 解释到 iOS 的内存管理,以及 Block 相关的原理.源码. 2 从 ARC 说起 说 iOS 的内存管理,就不得不从 ARC(Automatic Referen

《iOS应用开发》——2.3节内存管理

2.3 内存管理 iOS应用开发 我不是吓唬你们.在iOS 5.0系统之前,内存管理毫无疑问是iOS开发最困难的部分.简而言之,问题是这样的.无论何时你创建了一个变量,你就要在内存中给它分配一定的空间.对于局部变量来说,我们通常使用栈上的内存,这些内存是自动管理的,当函数返回时,函数中定义的任何局部变量都会从内存中自动删除. 这听起来很棒,但是栈有两个严重的局限.首先,它的空间非常有限,如果用尽了内存,应用程序就会崩溃.其次,这些变量很难共享.请记住,函数使用值传参和返回.这意味着所有传入函数或

iOS/OS X 内存管理(二):借助工具解决内存问题

上一篇博客iOS/OS X内存管理(一):基本概念与原理主要讲了iOS/OSX 内存管理中引用计数和内存管理规则,以及引入ARC新的内存管理机制之后如何选择ownership qualifiers(__strong.__weak.__unsafe_unretained和__autoreleasing)来管理内存.这篇我们主要关注在实际开发中会遇到哪些内存管理问题,以及如何使用工具来调试和解决. 在往下看之前请下载实例MemoryProblems,我们将以这个工程展开如何检查和解决内存问题. 悬挂

IOS中内存管理那些事_IOS

Objective-C 和 Swift 语言的内存管理方式都是基于引用计数「Reference Counting」的,引用计数是一个简单而有效管理对象生命周期的方式.引用计数分为手动引用计数「ARC: AutomaticReference Counting」和自动引用计数「MRC: Manual Reference Counting」,现在都是用 ARC 了,但是我们还是很有必要了解 MRC. 1. 引用计数的原理是什么? 当我们创建一个新对象时,他的引用计数为1: 当有一个新的指针指向这个对象