[objective-c]教程四-----內存管理(Memory Manage)

改定履歷:

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章