1. 程式人生 > >iOS OC記憶體管理、ARC、property屬性、__strong、__weak、__block——iOS 編碼複習(一)

iOS OC記憶體管理、ARC、property屬性、__strong、__weak、__block——iOS 編碼複習(一)

首先來聊聊記憶體管理。因為是先有了記憶體管理這個東西,才慢慢的有了ARC,而後才會有@property的各種屬性

聊到記憶體管理,我們就能知道iOS5之前,iOS的記憶體管理是MRC(手動記憶體管理)的。iOS5之後才有了ARC(自動記憶體管理)。

那我們就來看看MRC是怎麼做的:

在iOS中,每建立一個物件,物件的RC(引用計數)都是自動為1。

MRC中,物件呼叫retain時,RC就會+1;物件呼叫release時,RC就會-1;當RC的值為0時,系統會呼叫dealloc方法來銷燬物件。

所以MRC下的set 和 get方法是這樣的:

@property (nonatomic, retain) NSString * name;

- (void) setter:(NSString *)name

{

if(_name != name){

[_name release];

_name = [name retain];//或者copy

}

}

-(NSString *)name{

if(!_name){

_name = @"xxx";

}

return [[_name retain] autorelease];

}

在MRC下,@property關鍵字有:(這裡的使用都不是絕對的,只是一種選擇策略,比如NSString也可以用retain,要據情況而定)

1:assign、retain 和 copy:copy只用於NSString/block;retain用於除NSString/block以外的OC物件;assign用於非OC物件(基本資料型別、列舉等),當兩個物件相互引用的時候,一個要用retain,一個用assign。之所以NSString使用copy,就是因為NSMutableString的物件可以賦值給NSString,而父類指標可以指向子類物件,所以給這個屬性賦值的時候,無論是傳入可變物件還是不可變物件,那它都會是不可變的副本。如果使用strong,而傳入的物件是可變物件,那如果外部修改了這個可變物件,則就會修改到該屬性值。同理,NSArray、NSDictionary也應該使用copy。(copy會分配新的記憶體空間,retain或下面的strong只是對引用計數加一)

2:nonatomic 和 atomic:atomic的意思是原子的,它是指屬性儲存是執行緒安全(一次只有一個物件對它操作)的,但是atomic不一定就絕對執行緒安全了,比如一個可變陣列arr是執行緒安全的(atomic),但是[arr objectAtIndex:index]就不是執行緒安全的了。

3:readwrite 和 readonly:(這個就很好理解了)

4:getter 和 setter

ARC下新加了以下幾種@property屬性:

1:strong 與MRC下的retain是類似。引用計數+1

2:  weak, unsafe_unretained這兩個與assign差不多,不過也有區別,等下介紹;另外ARC下使用

assign的概率也是非常高的。

總結起來就是:記憶體管理基本是對引用計數的操作。對於property關鍵字,在MRC下,OC物件通常使用retain,非OC物件使用assign,迴圈引用的時候,一個使用retain,一個使用assign;在ARC下,OC物件通常使用strong,非OC物件通常使用assign,而weak就是為了對物件進行弱引用的,如迴圈引用的時候,一端使用strong,一端使用weak。

好,到這裡,本文的目的就基本達到了。不過,還想給大家分享點其他的乾貨,大部分也是看別人的總結的:

一:strong、weak、unsafe_unretained的區別

執行程式碼:

self.string1 = @"String 1";

   self.string2 = self.string1;

self.string1 = nil;

NSLog(@"String 2 = %@", self.string2);

1:strong:

@property (nonatomic, strong) NSString *string1;  

@property (nonatomic, strong) NSString *string2;

輸出 String 2 = String 1;因為引用計數加一

2:weak:

@property (nonatomic, strong) NSString *string1;   

@property (nonatomic, weak) NSString *string2;

輸出 String 2 = null因為wean的指標會指向同一個地址,引用計數不會加一,但是weak會將指標置為null,防止野指標出現。

3:unsafe_unretained:

@property (nonatomic, strong) NSString *string1;   

@property (nonatomic, unsafe_unretained) NSString *string2; 

注意這裡的程式會crash掉,不會自動將指標置為null,所以這就是它與weak的區別

二:__block、__weak、__strong的用法;避免迴圈引用: 其實我們都知道,這幾個東西就是使用block時為了避免迴圈引用才會經常用到的,所以按上面看到的經驗,一定要一端物件weak,才可以: 1)、__weak 與 __strong的結合使用避免迴圈引用 首先__weak是為了避免迴圈引用的,所以一般在使用block之前,可以使用__weak 來弱引用self,例如:

__weak  __typeof__(self)  weakSelf = self;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

[weakSelf dosomthing];

});

這裡沒有任何問題;但是下面

__weak  __typeof__(self)  weakSelf = self;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

[weakSelf doSomething];

[weakSelf doOtherSomething];

});

在執行完第一個doSomething之後,weakSelf有可能被釋放,這個時候就需要用到__strong了;

__weak  __typeof__(self)  weakSelf = self;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

__strong  __typeof__(self) strongSelf = weakSelf;

[strongSelf doSomething];

[strongelf doOtherSomething];

});

同上看到的,用__weak可以解決迴圈引用的問題。但是,如果block裡要執行多個函式,最好就要加上 __strong;同樣的這種巧妙的用法對變數也非常合適,使用過AFNetworking的人大概就見到過這樣的對變數的修飾。這樣即時block外部釋放了該變數,在block的生命週期裡,該變數還是可以使用的。

2)、問題來了,__block是幹嘛的??__block就與__weak正好相反了,它可以改變變數的作用域,使得變數的作用域擴充套件到block裡面。這個時候,就可以對block外部的變數進行操作了(__strong也有這個作用)。那麼__block是否可以避免迴圈引用呢??答案是肯定的,上程式碼:

__block  __typeof__(self)  blockSelf = self;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

[blockSelf doSomething];

[blockSelf doOtherSomething];

blockSelf = nil;

});

如上所示:把blockSelf置為nil是關鍵。

三、順帶說一下深拷貝和淺拷貝:copy就是淺拷貝,它只拷貝指標,mutableCopy是深拷貝,它會拷貝物件。就是不分父類子類。淺拷貝就是隻拷貝父類和子類的指標地址,深拷貝就是父類和子類的物件也都會拷貝。所以,你會發現歸檔,用的就是深拷貝。經常面試的人會問你,如何讓自定義的類具備拷貝功能,則只需要實現NSCoping協議就可以了。

好了。有點亂,希望後續可以多完善一下。也希望各位大牛指正