改定履历:
2012-4-26:--------------------------新建文本文档
2012-05-05:------------------------objective-c中,单独的"collection",意为"NSArry","NSDictionary"等这类"集合"容器.修正原来文中的错误翻译.个人认为翻译成"集合"或别的都不如"collection"来的准确,文中遇到即不再翻译.
正文:
objective-c是一门主要用于Apple's Mac OS X and iOS的面向对象编程语言.也是用于Apple Cocoa API的主要语言.本系列教程覆盖了objective-c的一些特定内容,包括:类,方法和内存管理.
本节原文地址
(译者注:IOS的内存都是在堆上开辟的)
objective-c提供了两种类型的内存管理.
1. 引用计数(Reference counting)(手工管理内存)
NSString* value = [[NSString alloc] init];
[value retain];
[value autorelease];
※ 当一个对象被分配内存空间后,其引用计数为1.
※ 开发者手动的对一个对象的引用计数增加或减少.
※ "retain"增加引用计数1;而"release"会减1.
※ 引用计数为0时对象会被删除,内存会被回收.
2.垃圾收集.(objective-c运行时自动管理内存)
※ objective-c运行时提供垃圾收集自动管理内存的选项.
※ 不需要引用计数的手工管理.
※ 支持Mac os X v10.5及以后版本.开发者应该为Max X开发基于垃圾收集机制的应用.
※ 不支持IOS.
※ 垃圾收集机制是代码编译时的可选特征(Garbage collection is an opt-in feature when compiling the code)
※ objective-c运行时将会决定任何一个对象没有被引用时释放它.(垃圾收集)
Objective-C 基于引用计数的内存管理
objective-c定义了一些基本的规则来决定"谁"应该释放一个对象.本指南提供了一份与基于引用计数的对象释放一致的编码惯例,在下列情况下,程序员有责任释放(release)或自动释放(autorelease)一个objective-c对象.
1. 某方法调用alloc, new, copy, 或 mutableCopy创建一个对象并返回该对象也应该释放(release)这个对象.
- getObject {
NSString* v1 = [[NSString alloc] init];
// 延迟对象V1的回收,直到方法调用链完成( Delay "v1" de-allocation until the complete method call chain is completed)
[v1 autorelease];
return v1;
}
※ autorelease并不立即回收对象内存.事实上,它会在整个方法调用链完成之后才会回收(free)内存.
※ 这会给调用者一个访问该对象的机会,而不用担心该对象已经释放(free--意为内存的回收)了自己.
id result = [myObject getObject];
// autorelease in getObject delay the deallocation
// Hence, it is still valid and accessible here
[result method1];
-----一定不要在getObject方法中去release该对象, 因为这将会回收该对象内存并导致接下来的调用无效.
2. 当一个对象做为另一个对象实例变量被赋值(set)的时候,正确地方法是实现一个"setter"方法管理引用计数
※ 在"setter"方法里release一个旧对象,retain新对象.
- (void) setValue: (NSString*)input
{
[value autorelease];
value = [value retain];
}
或
- (void) setValue: (NSString*)input
{
[input retain];
[value release];
value = input;
}
或
- (void) setValue: (NSString*)input
{
[value release];
value = input;
[value retain];
}
※ 如果输入参数与要被"set"的对象是同一个对象, 上面的代码不会过早的回收对象.
3. 在某种情况下, 一个方法可能会调用用"retain"方法来增加对象的引用计数.
※ 在同一个方法里,即使不是必须的,它(retain)也应该与release或autorelease匹配使用.
// Increment the reference count by 1
[s retain];
...
[s autorelease];
4. 当一个对象被回收(deallocated)时,其实例变量对象也应被回收.
- (void) dealloc
{
[value release];
[super dealloc];
}
※ 除以下情况外,在方法内分配的对象通常是保证有效的:
(1) 对象被从"collection"中移除,对象被删除
(2) 类对象被释放(release),其实例变量也会被释放(release)
※ 增加到"collections"(NSArry,NSDictionary)中的objects或keys被从中移除的时候,仍然会被自动地retain和release.
Objective-C Autorelease
立即释放(release)回收(de-allocates)一个objective-c对象后,在将来引用该对象会是无效的."autorelease"将objective-c对象注册到"autorelease pool"中.实际上,"autorelease pool"存在于程序员创建的每一个X-code工程中."autorelease pool"中的对象只有在"pool"自己被释放的时候才会释放(release),而这通常是在方法调用链(the chain of method calls)完成之后才做的操作.这种推迟的释放(release)操作简化了返回对象给调用者的内存管理.用于X-CODE工程的应用程序开发包在一个事件(例如一个"mouse down"事件)开始的时候会自动地创建一个"autorelease pool"(NSAutoreleasePool实例).该内存池会在该事件处理完成后"清空"(drain)一次.
下面的例子演示了如何管理从一个方法返回一个objective-c对象.
- myCallee {
...
id newObject = [[NSString alloc] init];
//在返回方法内分配的objective-c对象之前,应先"autorelease"
[newObject autorelease];
return newObject;
}
- 方法以alloc,new,copy或者mutableCopy创建返回的对象,调用者拥有其所有权
- 根据objective-c内存编码指南,该方法也有责任释放(release)这个对象.
- 使用"autorelease"延迟释放(release),这样调用者仍然可以引用返回的对象.
调用者:
- myCaller {
...
id obj = [myObject createANewInstance];
// obj is still valid even autorelease is called (not true if myCallee make a message call like [newObject release])
[obj someMehtod];
// Does not need to call [myObject release];
}
※ 对象"obj"仍然是有效的,因为"autorelease"还没有真正释放(release)该对象.
※ 对象"obj"在"autorelease pool"被释放(release)后会被释放(release).
※ 对于一个X-CODE工程来说,"autorelease pool"会在相应的事件完成之后释放(release).
※ 因为该对象并非由调用者以alloc, new, copy, 或 mutableCopy创建返回的,根据objective-c编程指南,调用者方法无须对该对象的释放负责.
手动创建autorelease pool
应用开发包会自动处理autorelease.如果程序员需要自定义"autorelease pool",下面的例子演示了如何创建和销毁一个"autorelease pool".
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString* obj = [[NSString alloc] init];
[obj autorelease];
[pool drain];
引用计数的通用做法
※ 对本地对象来说:
(1) 如果本地对象是返回给调用者的,在返回(return)对象之前要"autorelease"它.
(2) 如果本地对象不是返回给调用者的,在返回(return)之前要"release"它.
※ 对于类实例变量来说,在"dealloc"中 "release"该实例变量.
在使用"setter"方法时,应谨慎对待引用计数
//下面是错误的使用例子.- method1 {
...
id newObject = [[NSString alloc] init];
// Wrong. both init and the setter will increment the reference count to 2
[self setValue:newObject];
...
}
//下面是正确的分配对象的例子
- method1 {
...
id newObject = [[NSString alloc] init];
// Set the instance variable directly
value = newObject;
...
}
或者可以手动减少对象引用计数
- method1 {
...
id newObject = [[NSString alloc] init];
[self setValue:newObject];
[newObject release];
...
}
"getter"方法的内存管理
objective-c可以为属性(property)声明自动的创建内存管理代码.
@property (retain) NSDate *value;
如果手动实现的话,如下:
- (NSString*) value {
return [[value retain] autorelease];
}
objective-c collection类引用计数
for (i = 0; i < 5; i++) {
NSNumber *n = [[NSNumber alloc] initWithInteger: i];
[myArray addObject:n];
[n release];
}
"addObject"会增加对象引用计数.
---------------
补充:
IOS不支持垃圾收集机制,仅适用于Mac 0S X v10.5 或以后版本.
垃圾收集缺省是关闭的.如果想启用该机制,使用以下代码编译:
-fobjc-gc-only
如果工程既使用垃圾收集也使用引用计数,用以下代码编译:
-fobjc-gc