我们都知道在C/C++语言中,堆内存是应该由程序员负责释放的,编译器并不负责释放程序员自己分配的堆内存空间;而在Objective-C语言 中,类实例的释放是通过release方法进行释放的,如果是Autorelease Pool中的实例,程序员还不必自己手动释放相应的内存空间,这点对于习惯在iPhone中使用C/C++风格编写程序的程序员来说,无疑是有点迷惑性 的,例如下面的代码:
view plaincopy to clipboardprint?
- #import <Foundation/Foundation.h>
- @interface MemoryManager : NSObject {
- @public
- char* memory;
- }
- @end
view plaincopy to clipboardprint?
- #import "MemoryManager.h"
- @implementation MemoryManager
- -(id) init
- {
- if (self = [super init])
- {
- }
- return self;
- }
- - (void)dealloc
- {
- NSLog(@"dealloc MemoryManager");
- }
- @end
笔者在MemoryManager中声明了一个char*的变量,并且这个变量的访问权限是公开的(@public属性),那么如果在别的类中显示的为 char*分配了内存空间,这些空间应该交给谁负责释放?是应该由程序员自己调用free函数进行释放,还是应该由实例调用release方法进行释放?
代码如下:
view plaincopy to clipboardprint?
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
- // Override point for customization after application launch.
- MemoryManager* manager = [[MemoryManager alloc] init];
- manager->memory = (char*)malloc(5);
- NSLog(@"memory address :%x",(manager->memory));
- memcpy(manager->memory,"abcd",4);
- [manager release];
- [self.window makeKeyAndVisible];
- return YES;
- }
很明显,如果在上面的代码中调用了free(manager->memory)来显示的释放内存,如果后面的代码还在使用这块内存空间,无疑会造成内存管理的混乱,如下代码:
view plaincopy to clipboardprint?
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
- // Override point for customization after application launch.
- MemoryManager* manager = [[MemoryManager alloc] init];
- manager->memory = (char*)malloc(5);
- NSLog(@"memory address :%x",(manager->memory));
- memcpy(manager->memory,"abcd",4);
- NSMutableArray* tempArray = [[NSMutableArray alloc] initWithCapacity:10];
- [tempArray addObject:manager];
- free(manager->memory);
- [manager release];
- [self.window makeKeyAndVisible];
- return YES;
- }
在上面的代码中,笔者把manager实例添加到一个NSMutableArray实例中,然后释放了manager->memory所引用的内存 空间,但是tempArray实例在以后的代码中可能还会使用manager->memory进行内存访问,那么程序无疑会发生crash;所以我 们需要保证manager->memory的生命周期和它所处的实例的生命周期一致,这样无论任何时候通过manager->memory访 问内存空间都会得到正确的结果,我们知道C++中是通过析构函数来保证这点的,通过调用delete,那么编译器会调用相应对象的析构函数进行对象内部堆 空间的释放。
其实在iPhone中,release的作用和delete是一样的,它会调用对象的dealloc方法,唯一不同的是release是基于引用计数的, 在调用release方法的时候,只有引用内存空间的计数为0时才会调用实例的release方法进行内存释放,由于[tempArray addObject:manager]对manager进行了retain操作,所以manager实例的引用计数为2,在tempArray使用完 manager对象后,通过调用release方法就可以释放manager对象及其内部的memory指针所引用的内存堆空间。
于是很显然的是,程序员需要在dealloc方法中管理类对象的内存指针以及相应的内存空间,合理的代码如下:
view plaincopy to clipboardprint?
- #import "MemoryManager.h"
- @implementation MemoryManager
- -(id) init
- {
- if (self = [super init])
- {
- }
- return self;
- }
- - (void)dealloc
- {
- NSLog(@"dealloc MemoryManager");
- free(memory);
- }
- @end
这样无论程序员在什么时候使用MemoryManager来产生对象,那么只需要记住释放相应的对象,而这个对象内部memory指针所引用的内存空间也相应的被释放了,这无疑是很好的编程习惯!
测试代码下载地址:http://www.pocketcn.com/forum.php?mod=viewthread&tid=426&page=1&extra=#pid3098