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下使用
總結起來就是:記憶體管理基本是對引用計數的操作。對於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協議就可以了。好了。有點亂,希望後續可以多完善一下。也希望各位大牛指正