剖析Objective-C内存管理规则
详解Objective-C 2.0 关于Objective-C内存管理规则是本文要介绍的内容,不多说,先来看内容。Objective-C 2.0增加了一些新的东西,包括属性和垃圾回收。那么,我们在学习Objective-C 2.0之前,最好应该先了解,从前是什么样的,为什么Objective-C 2.0要增加这些支持。
这一切都跟Cocoa内存的管理规则有关系,我们知道,Objective-C中所有变量都定义为指针。指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址,如果使用不当,就会出错或者造成内存的泄露。要了解这些,就需要看看其内存管理的规则到底是什么样的。
这篇文章也应该做为苹果开发工具中提供的性能调试工具Instruments使用前必读知识进行阅读。要知道,如果你使用Objective-C 2.0,那么本文描述的大部分工作你都不需要自己去处理了。但是这并不意味着你可以不了解它,相反,只有你对内存管理规则更加了解,你才能更好地使用Objective-C 2.0带来的便利。
当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
- //我们可以认为它会被自动释放
- @interface Counter : NSObject
- {
- NSNumber *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;
- }
- (void)dealloc
- {
- [self setCount:nil];
- [super dealloc];
- }
- (void)reset
- {
- NSNumber *zero = [NSNumber numberWithInt:0];
- [self setCount:zero];
- }
- (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];
- }
- - (void)reset
- {
- NSNumber *zero = [NSNumber numberWithInt:0];
- [self setCount:zero];
- [zero release];
- }
- 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];
- }