iOS開發中各種關鍵字的區別

weixin_33912246發表於2017-10-17

1.一些概念

1.淺Copy:指標的複製,只是多了一個指向這塊記憶體的指標,共用一塊記憶體。
深Copy:記憶體的複製,兩塊記憶體是完全不同的,
也就是兩個物件指標分別指向不同的記憶體,互不干涉。

2.atomic是Objc使用的一種執行緒保護技術,
基本上來講,是防止在寫未完成的時候被另外一個執行緒讀取,
造成資料錯誤。而這種機制是耗費系統資源的,
所以在iPhone這種小型裝置上,如果沒有使用多執行緒間的通訊程式設計,
那麼nonatomic是一個非常好的選擇。

2.各種屬性的解析

weak:

<修飾Object型別,ARC下修飾delegate屬性>
1.在ARC環境下,所有指向這個物件的weak指標都將被置為nil。

這個特性很有用,很多codeer都有被指標指向已釋放的物件所造成的EXC_BAD_ACCESS困擾過,使用ARC以後,不論是strong還是weak型別的指標,都不會再指向一個已經銷燬的物件,從根本上解決了意外釋放導致的crash。

2.修飾Object型別,修飾的物件在釋放後,指標地址會被置為nil,是一種弱引用。在ARC環境下,為避免迴圈引用,往往會把delegate屬性用weak修飾;在MRC下使用assign修飾。weak和strong不同的是:當一個物件不再有strong型別的指標指向它的時候,它就會被釋放,即使還有weak型指標指向它,那麼這些weak型指標也將被清除。

assign:

< 用於非指標變數。用於基礎資料型別 (例如NSInteger)和C資料型別(int, float, double, char, 等),另外還有id >
1.用於對基本資料型別進行復制操作,不更改引用計數。也可以用來修飾物件,但是,被assign修飾的物件在釋放後,指標的地址還是存在的,也就是說指標並沒有被置為nil,成為野指標。如果後續在分配物件到堆上的某塊記憶體時,正好分到這塊地址,程式就會crash。之所以可以修飾基本資料型別,因為基本資料型別一般分配在棧上,棧的記憶體會由系統自動處理,不會造成野指標。

我們常見的id delegate往往是用assign方式的屬性而不是retain方式的屬性,賦值不會增加引用計數,就是為了防止delegation兩端產生不必要的迴圈引用。如果一個UITableViewController 物件a通過retain獲取了UITableView物件b的所有權,這個UITableView物件b的delegate又是a, 如果這個delegate是retain方式的,那基本上就沒有機會釋放這兩個物件了。自己在設計使用delegate模式時,也要注意這點。因為迴圈引用而產生的記憶體洩露也是Instrument無法發現的,所以要特別小心。

copy:

修飾NSString、NSArray、NSDictionary等有對應可變型別的物件
建立一個索引計數為1的物件,然後釋放舊物件。

是內容拷貝,會在記憶體裡拷貝一份物件,兩個指標指向不同的記憶體地址。一般用來修飾NSString、NSArray等有對應可變型別的物件,因為他們有可能和對應的可變型別(NSMutableString)之間進行賦值操作,為確保物件中的字串不被修改 ,應該在設定屬性是拷貝一份。而若用strong修飾,如果物件在外部被修改了,會影響到屬性。

在不可變物件之間進行轉換,strong與copy作用是一樣的,但是如果在不可變與可變之間進行操作,我比較推薦copy,這也就是為什麼很多地方用copy,而不是strong修飾NSString,NSArray等存在對應不可變型別的物件了,避免出現意外的資料操作.

strong

ARC下的strong等同於MRC下的retain都會把物件引用計數加1。
1.在ARC環境下,只要某一物件被一個strong指標指向,該物件就不會被銷燬。如果物件沒有被任何strong指標指向,那麼就會被銷燬。在預設情況下,所有的例項變數和區域性變數都是strong型別的。可以說strong型別的指標在行為上跟MRC下得retain是比較相似的

retain

釋放舊的物件,將舊物件的值賦予輸入物件,再提高輸入物件的索引計數為1

在MRC中,你需要自己retain一個想要保持的物件,ARC環境下就不需要了。現在唯一要做的就是用一個指標指向這個物件,只要指標沒有被重置為空,物件就會一直在堆上。當指標指向新值的時候,原來的物件就會被release一次。這對例項變數,sunthesize的變數或者是區域性變數都是實用的。

3.屬性之間區別

在iOS開發中我們知道一般nsstring,就用copy,定義一個模型物件,就用strong,只是賦值的,例如int、double、char 以及CGRect類似的就用assign。但具體為什麼可能很多人不是很清楚。
這裡進行簡單的解釋:
這些關鍵字基本上是針對屬性的set方法。
當用copy時,set方法會先release舊值,再copy一個新的物件,reference count 為1(減少了對上下文的依賴);當用assign,直接賦值,無retain操作。當用retain,release舊值,retain新值;

strong與weak的區別

strong類似於retain,會將物件的引用計數器+1,分配記憶體地址。
weak類似於指標,只是單純的指向某個地址,但是本身並未分配記憶體地址。當指向的地址被銷燬時,該指標會自動nil。
例子:

  1. @synthesize string1;
  2. @synthesize string2;

來猜一下,下面輸出是什麼?

1.    self.string1 = [[NSString alloc] initWithUTF8String:"string 1"];   
2.    self.string2 = self.string1;   
3.    self.string1 = nil;  
4.    NSLog(@"String 2 = %@", self.string2);  

結果是:String 2 = null

分析一下,由於self.string1與self.string2指向同一地址,且string2沒有retain記憶體地址,而 self.string1=nil釋放了記憶體,所以string1為nil。宣告為weak的指標,指標指向的地址一旦被釋放,這些指標都將被賦值為 nil。這樣的好處能有效的防止野指標。在c/c++開發過程中,指標的空間釋放了後,都要將指標賦為NULL. 在這兒用weak關鍵字做了這一步。

assign和weak的區別

對於assign來說,一是非指標變數,比如說NSInteger之類的基礎資料型別、C資料型別,還有就是避免出現迴圈引用的時候,
對於weak,其和assign差不多,但是它多了一點,就是,它會自動對該型別變數設定為nil。

PS:最後如果各位大佬發現那裡有問題歡迎批評指出,覺得有用點個喜歡~

相關文章