天天看點

iOS記憶體管理知識點

###PART1: ARC的修飾符

ARC主要提供了4種修飾符,他們分别是:

__strong

__weak

__autoreleasing

__unsafe_unretained

####__strong 表示引用為強引用。對應在定義property時的"strong"。所有對象隻有當沒有任何一個強引用指向時,才會被釋放。 注意:如果在聲明引用時不加修飾符,那麼引用将預設是強引用。當需要釋放強引用指向的對象時,需要将強引用置nil。

####__weak 表示引用為弱引用。對應在定義property時用的"weak"。弱引用不會影響對象的釋放,即隻要對象沒有任何強引用指向(弱引用不會持有對象),即使有100個弱引用對象指向也沒用,該對象依然會被釋放。不過好在,對象在被釋放的同時,指向它的弱引用會自動被置nil,這個技術叫zeroing weak pointer。這樣有效得防止無效指針、野指針的産生。__weak一般用在delegate關系中防止循環引用或者用來修飾指向由Interface Builder編輯與生成的UI控件。

####__autoreleasing 表示在autorelease pool中自動釋放對象的引用,和MRC時代調用autorelease的用法相同。定義property時不能使用這個修飾符,任何一個對象的property都不應該是autorelease型的。

一個常見的誤解是,在ARC中沒有autorelease,因為這樣一個“自動釋放”看起來好像有點多餘。這個誤解可能源自于将ARC的“自動”和autorelease“自動”的混淆。其實你隻要看一下每個iOS App的main.m檔案就能知道,autorelease不僅好好的存在着,并且變得更fashion了:不需要再手工被建立,也不需要再顯式得調用[drain]方法釋放記憶體池。

以下兩行代碼的意義是相同的。

NSString *str = [[[NSString alloc] initWithFormat:@"hehe"] autorelease]; // MRC
NSString *__autoreleasing str = [[NSString alloc] initWithFormat:@"hehe"]; // ARC
複制代碼
           

__autoreleasing在ARC中主要用在參數傳遞傳回值(out-parameters)和引用傳遞參數(pass-by-reference)的情況下。 __autoreleasing

> is used to denote arguments that are passed by reference (id * ) and are autoreleased on return.

比如常用的NSError的使用:

NSError *__autoreleasing error; 
if (![data writeToFile:filename options:NSDataWritingAtomic error:&error]) { 
  NSLog(@"Error: %@", error); 
}
複制代碼
           

在上面的writeToFile方法中error參數的類型為(NSError *__autoreleasing *)

注意,如果你的error定義為了strong型,那麼,編譯器會幫你隐式地做如下事情,保證最終傳入函數的參數依然是個__autoreleasing類型的引用。

NSError *error; 
NSError *__autoreleasing tempError = error; // 編譯器添加 
if (![data writeToFile:filename options:NSDataWritingAtomic error:&tempError]) { 
  error = tempError; // 編譯器添加 
  NSLog(@"Error: %@", error); 
}
複制代碼
           

是以為了提高效率,避免這種情況,我們一般在定義error的時候将其聲明為__autoreleasing類型的:

NSError *__autoreleasing error;
複制代碼
           

在這裡,加上__autoreleasing之後,相當于在MRC中對傳回值error做了如下事情:

*error = [[[NSError alloc] init] autorelease];
複制代碼
           

*error指向的對象在建立出來後,被放入到了autoreleasing pool中,等待使用結束後的自動釋放,函數外error的使用者并不需要關心*error指向對象的釋放。

另外一點,在ARC中,所有這種指針的指針 (NSError **)的函數參數如果不加修飾符,編譯器會預設将他們認定為__autoreleasing類型.

####__unsafe_unretained 忽略~

####補充一點 蘋果的文檔中明确地寫道:

You should decorate variables correctly. When using qualifiers in an object variable declaration, the correct format is : ClassName * qualifier variableName;

按照這個說明,要定義一個weak型的NSString引用,它的寫法應該是:

NSString * __weak str = @"xx";
複制代碼
           

而不應該是:

__weak NSString *str = @"xx";  
複制代碼
           

###PART2: __weak使用注意

通路附有__weak修飾符的變量時,該變量會被自動注冊到autoreleasepool中, 這種等價是編譯器自動做的轉換,原因是__weak修飾符支援有對象的弱引用,在通路引用對象的過程中,該對象可能被釋放。而如果将該對象加入到autoreleasepool中,在pool被釋放之前, 對該對象的引用都是有效的。

但是大量的使用__weak修飾符的變量, 注冊到autoreleaspool的對象也會大大增加, 是以在使用__weak修飾符的變量時, 最好先暫時指派給__strong修飾符的變量後在使用

###PART3: NSArray array/new/@[]/alloc-init的差別

所有這些方法的結果其實都是一樣的,你得到一個新的空的不可變數組. 但不同的方法有不同的記憶體管理方式. 現在我們都是使用ARC, 是以說最終是沒有差別的, 但在ARC之前我們要正确适時的調用

retain

,

release

,

autorelease

方法.

[NSArray new] 和 **[[NSArray alloc] init]**傳回一個數組,并且引用計數+1. 在ARC之前, 你需要自己

release

或者

autorelease

數組, 否則會導緻記憶體洩漏.

[NSArray array] 和 @[] 傳回了一個已經調用了autorelease的數組, 引用計數為0(不持有), 你必須手動調用

retain

方法來保留它,否則将在目前自動釋放池銷毀時被釋放。 [NSMutableArray array]相當于[[[NSMutableArray alloc] init] autorelease]

http://www.cnblogs.com/flyFreeZn/p/4264220.html https://stackoverflow.com/questions/33297171/difference-between-nsarray-array-new-alloc-init

繼續閱讀