改定履歷:
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