【iOS】定義@property時常用的修飾詞介紹
iOS程式設計中,定義成員變數常用格式如下:
@property (nonatomic, strong) UILabel *label;
常用的修飾詞有atomic,nonatomic,copy,assign,strong,weak,readonly,readwrite等。面試中也會常常被問到這些修飾詞的含義及其之間的區別,其本質就是iOS的記憶體管理,下面會詳細介紹每個詞的特性和它們的區別,還會補充__block與__weak的相關知識。
atomic
- 屬性的預設屬性,當前執行緒進行到一半其他執行緒來訪問當前執行緒,可以保證先執行完畢當前執行緒,但只是保證setter/getter完整,不是執行緒安全的。
- atomic雖然對屬性的讀和寫是原子性的,但是仍然可能出現執行緒錯誤,比如:@property(atomic,strong)NSMutableArray *mArray;如果一個執行緒對mArray迴圈讀資料,另一個執行緒迴圈寫資料,那麼[self.mArray objectAtIndex:index]就不是執行緒安全的。可以用加鎖的方法來解決這個執行緒不安全的問題。
-
atomic的作用只是給getter和setter加了個鎖,atomic只能保證程式碼進入getter或者setter函式內部時是安全的,一旦出了getter和setter,多執行緒安全只能靠程式設計師自己保障了。所以atomic屬性和使用property的多執行緒安全並沒什麼直接的聯絡。另外,atomic由於加鎖也會帶來一些效能損耗,所以我們在編寫iOS程式碼的時候,一般宣告property為nonatomic,在需要做多執行緒安全的場景,自己去額外加鎖做同步。
nonatomic
- 屬性的非預設屬性,需要編碼者手動寫。不僅是執行緒不安全的,也無法保證setter/getter的完整,多個執行緒同時訪問這個屬性,結果無法預計。
-
nonatomic速度比atomic速度快,所以通常用nonatomic。
copy
- 常見的copy宣告的是NSString和block。
- copy生成的物件是一個新的物件,不是引用原來的物件,對原物件的引用計數無影響。
- 使用copy建立的新物件也是強引用,使用完成後需要負責釋放該物件。
- copy特性可以減少物件對上下文的依賴。新物件、原始物件中任一物件的值的改變不會影響另一個物件的值。
-
以下程式碼可驗證copy修飾(NSString的實現遵循了NSCopy協議,所以預設為copy)的各個物件值的改變互不影響。
-(void)stringCopyTest{ NSString * A = @"A"; NSString * B = A; NSString * C = [A copy]; NSLog(@"A === %@ B === %@ C === %@",A,B,C); A = @"AB"; NSLog(@"A === %@ B === %@ C === %@",A,B,C); B = @"ABC"; NSLog(@"A === %@ B === %@ C === %@",A,B,C); C = @"abcd"; NSLog(@"A === %@ B === %@ C === %@",A,B,C); }
assign
- 只是引用,只返回指標。用於float、int等基本資料型別。
- 如果用來修飾物件,編譯會產生警告:Assigning retained object to unsafe property; object will be released after assignment。在釋放之後,指標的地址還存在,也就是說指標並沒有被置為nil,會造成野指標。物件一般分配在堆上的某塊記憶體,如果後續的記憶體分配中用到了這塊地址,就會造成crash。
-
由於基本資料型別一般是分配在棧上的,棧的記憶體會由系統自己處理,不會造成野指標,所以assign可以用來修飾基本資料型別。
strong
- 屬性的預設屬性,iOS引入ARC之後,用strong代替了retain。
- 建立一個強引用的指標,引用物件的引用計數加1。strong特性表示兩個物件記憶體地址相同(建立一個指標,進行指標拷貝),內容會一直保持相同,直到更改一方的記憶體地址,或者將其置為nil。
- 除了NSString之外的例項變數和區域性變數都預設是strong。
-
以下程式碼可以驗證如果有多個strong物件同時引用一個屬性,任一物件對該屬性的修改都會影響其他物件獲取的值。
-(void)strongTest{ NSMutableArray * marray1 = [NSMutableArray arrayWithArray:@[@"aaa"]]; NSMutableArray * array = marray1; NSLog(@"1 === %@ 2 === %@",marray1,array); [marray1 addObject:@"bbb"]; NSLog(@"1 === %@ 2 === %@",marray1,array); [array addObject:@"ccc"]; NSLog(@"1 === %@ 2 === %@",marray1,array); }
weak
- 弱引用,物件引用技術不會加1。weak修飾的物件被釋放之後,會自動置為nil,像nil傳送訊息,什麼都不會執行,程式也不會crash。
-
代理使用weak。delegate幾乎一直持有代理物件,所以代理物件應該對代理使用weak,否則會形成迴圈引用。但也有例外,如果代理物件的生命週期比較短,代理物件也可以使用strong。
readonly
-
變數的非預設屬性,只有可讀方法,即只有getter方法。
readwrite
- 變數的預設屬性,會生成setter方法和getter方法。
-
如果希望一個屬性只允許自己讀寫,而對所有外部檔案都是隻讀的,可以在介面部分宣告該屬性為readonly型別,最後在私有介面部分重寫該屬性為readwrite型別。
assign 與weak
- assign適用於基本資料型別,weak適用於NSObject物件,並且是一個弱引用。
-
assign修飾的物件被釋放後記憶體地址不會被釋放,會造成野指標;weak修飾的物件被釋放後,物件會被置為nil,不會出現記憶體洩漏的問題。
strong 與copy
- 通過上面的程式碼可能看出strong的兩個指標會指向同一個記憶體地址;copy會在記憶體裡拷貝一份物件,兩個指標指向不同的記憶體地址。
-
block的迴圈引用並不是strong導致的,在ARC下,系統底層也會做一次copy操作使block從棧區複製一塊記憶體空間到堆區,所以strong和copy在對block的修飾上是沒有本質區別。
strong與weak
- strong是強引用,會讓物件的引用計數+1;weak是弱引用,物件的引用計數不變。
- 幫助理解二者區別的例子:假設物件是一條小狗,小狗想跑。strong型別就像是拴狗的繩子,只要有一條繩子栓住狗,它就不能跑走,如果有五條繩子拴著同一條狗(五個strong型別指向同一個物件),只有當五條繩子都釋放狗才可以跑走。weak型別就像是小孩子看著小狗說:看這裡有小狗。只要還有繩子拴著小狗,小孩子們就可以繼續指著小狗說:看這裡有小狗。當繩子釋放了的時候,不管有多少小孩子依舊在指著小狗說:看這裡的小狗。小狗都會跑掉。當最後一個strong指標不再指向這個物件,這個物件就會被釋放,此時,所有指向這個物件的weak指標都將被清空且置為nil。
# __block與__weak - __block是用來修飾一個變數,這個變數可以在block中被修改。
- 使用__block修飾的變數在block程式碼塊中會被retain(ARC下會retain,MRC下不會retain)。
-
使用__weak修飾的變數不會在block程式碼塊中被retain。同時,在ARC下,要避免出現迴圈引用可以使用如下程式碼:
__weak typedof(self) weakSelf = self;
整理這些的時候也寫了一些程式碼來驗證,發現東西其實很多,往細處想只會發現自己不會的更多。面試的時候經常會聽到的一句話就是說一下記憶體管理,以前都會很懵,感覺記憶體管理無從說起。現在慢慢理解,其實這些東西都是記憶體管理的體現,再遇到問這個問題的,這些都能說上來應該也不算太差。
相關文章
- 四種許可權修飾符的簡單介紹
- Java 常用修飾符Java
- 中文分詞原理及常用Python中文分詞庫介紹中文分詞Python
- iOS-日常開發常用巨集定義iOS
- Django 常用的自定義裝飾器Django
- 自定義View:Paint的常用屬性介紹及使用ViewAI
- python中的裝飾器介紹Python
- java中被final修飾的常用類有哪些?Java
- BBED修復資料庫常用命令介紹資料庫
- 介紹使用WordPress時10個常用的MySQL查詢MySql
- 摘:裝飾器@property @setter
- java常用修飾符(隨堂筆記)Java筆記
- yocto-名詞介紹
- C++繼承時的修飾符C++繼承
- SVG XML 格式定義圖形入門介紹SVGXML
- 軟體定義汽車之SOME/IP介紹
- 常用鎖原理的介紹(上)
- SpringMvc的常用註解介紹SpringMVC
- 裝飾器vue-property-decoratorVue
- 簡單介紹Shell中的定時任務 crontab
- etcd 常用操作介紹
- Flutter 常用 Widget 介紹Flutter
- JavaScript常用物件介紹JavaScript物件
- linux常用指令介紹Linux
- final修飾和static final修飾的區別
- java分詞工具hanlp介紹Java分詞HanLP
- Java常用的5大框架介紹!Java框架
- iOS Runtime介紹和使用iOS
- iOS UIButton之UIControlEvents介紹iOSUI
- Swift iOS:AutoLayout 快速介紹SwiftiOS
- Python的黑魔法@property裝飾器的使用技巧Python
- iOS面試之@propertyiOS面試
- oracle常用函式介紹Oracle函式
- logstash常用外掛介紹
- rematch常用外掛介紹REM
- Flutter 常用功能介紹Flutter
- DNS常用術語介紹DNS
- HTML常用標籤介紹HTML