OC的屬性和關鍵字總結
屬性
@property = ivar(成員變數)+set方法+get方法 由編譯器自動組成
ps. kvc和kvo對區域性成員變數無效,就是因為區域性成員變數沒有set/get方法。
@property有兩個對應的詞,一個是@synthesize(預設),一個是@dynamic。
- @synthesize的語義是如果你沒有手動實現set方法和get方法,編譯器會自動為你加上這兩個方法。
- @dynamic告訴編譯器,屬性的set/get方法由使用者自己實現,不自動生成。假如一個屬性被宣告為@dynamic var,然而沒有提供set/get方法,編譯的時候沒問題,但是當程式執行到self.var = someVar,由於缺少set方法會導致crash;或者執行到someVar = var時,由於缺少get方法同樣會導致崩潰。編譯時沒問題,執行時才執行相應的方法,這就是所謂的動態繫結。
關鍵字
- assign:只是簡單的賦值操作,指向同一個記憶體區,一個地方的變了,其他的也跟著變。引用計數不變。
- retain:淺拷貝,指標拷貝,引用計數+1;
- weak:ARC引入,跟assign修飾符功能一樣,簡單的賦值操作,只是當物件被釋放時,會將weak引用置為nil,防止野指標。assign不能修飾物件,weak可以修飾物件。
- strong:ARC引入,用來替代retain。
- copy:深拷貝,地址拷貝,舊的引用計數不變,新的引用計數為1;
- readwrite:可讀寫,預設生成set/get方法;
- readonly:只讀,預設生成get方法;
- nonatomic:非原子性;
- atomic:原子性,非執行緒安全;
基本型別預設關鍵字:atomic,readwrite,assign;
OC物件預設關鍵字:atomic,readwrite,strong;
這裡解釋一下atomic為什麼是執行緒不安全的。
atomic本質上是對物件的set/get方法加鎖,當引用A的set/get方法和引用B的set/get方法同時操作時,雖然加了鎖,但是引用Bget到的可能是引用Aset之後的,所以執行緒不安全,且消耗效能,所以建議不用atomic關鍵字。
weak的實現原理。
個人理解,系統內部有一個全域性的CFMutableDictionary例項,來儲存每個物件的weak指標列表,key是物件地址,value是CFMutableSet型別,多個該物件的weak指標。
當物件的引用計數為0時,去這個全域性的字典,通過物件地址找到所有weak指標,將其置為nil。
類似kvo的實現原理, 基於runtime實現。當物件存在weak指標時,我們可以將這個例項指向一個新建立的派生類,然後修改這個派生類的release方法,在release方法中,實現上一步所構想的事情。
可變型別和不可變型別的修飾符
可變型別只能用淺拷貝(strong),如果用深拷貝(copy),初始化會報錯,因為生成的是不可變型別。
不可變型別深淺拷貝都可以,copy不會受其他物件影響,但是會在setter方法中進行判斷,傳入的是否可變,如果是可變就分配新的記憶體再賦值,如果是不可變直接賦值地址。而實際開發中大量使用的是不可變的,所以使用strong可以提升提升效能(減少一次判斷),但是會受其他物件影響。
@interface Person : NSObject @property (strong, nonatomic) NSArray *bookArray1; @property (copy, nonatomic) NSArray *bookArray2; @end @implementation Person //省略setter方法 @end //Person呼叫 main(){ NSMutableArray *books = [@[@"book1"] mutableCopy]; Person *person = [[Person alloc] init]; person.bookArray1 = books; person.bookArray2 = books; [books addObject:@"book2"]; NSLog(@"bookArray1:%@",person.bookArray1); NSLog(@"bookArray2:%@",person.bookArray2); }
注意block和delegate的修飾符
block用copy修飾,原因是為了延長作用域。一般情況下你不需要自行呼叫copy或者retain一個block. 只有當你需要在block定義域以外的地方使用時才需要copy. Copy將block從記憶體棧區移到堆區.其實block使用copy是MRC留下來的也算是一個傳統吧, 在MRC下, 如上述, 在方法中的block建立在棧區, 使用copy就能把他放到堆區, 這樣在作用域外呼叫該block程式就不會崩潰.但在ARC下, 使用copy與strong其實都一樣, 因為block的retain就是用copy來實現的, 所以block使用copy還能裝裝逼, 說明自己是從MRC下走過來的。
delegate用weak修飾,為了防止迴圈引用。
迴圈引用
你中有我,我中有你,等到釋放的時候,我等你釋放,你等我釋放,造成迴圈引用。特別注意block,NSTimer,和delegate。
block解決迴圈引用
在非arc下,可以給區域性變數加一個__block修飾符來弱引用,因為非arc下,__block修飾的變數不會自動retain;在arc下,由於__block修飾的變數一樣會被block retain,所以需要__weak來解決迴圈引用的問題。
當block內部有延時操作時,需要在內部對__weak修飾弱指標再__strong強引用一下。
Better Late Than Never!
努力是為了當機會來臨時不會錯失機會。
共勉!