stackoverflow上關(guān)于Objective-C關(guān)注度比較高的問題系列
鏈接
iOS中屬性修飾符
原文鏈接《Variable property attributes or Modifiers in iOS》
該問題在stackoverflow中的討論鏈接
本文Github鏈接
關(guān)鍵詞
atomic, nonatomic, strong, retain, weak, unsafe_unretained, assign, copy, readonly, readwrite
屬性的修飾符指示數(shù)據(jù)的內(nèi)存管理和讀寫權(quán)限。
使用接口方法獲取或者設(shè)置屬性的值。
屬性修飾符有以下幾種:
- atomic
- nonatomic
- strong/retain
- weak = unsafe_unretained
- retain
- assign
- unsafe_unretained
- copy
- readonly
- readwrite
其中默認(rèn)的修飾符是:
- atomic
- stong
- assign
- readwrite
1.原子性(atomic)
1) atomic
- atomic 意味著只有一個(gè)線程訪問變量(靜態(tài)類型);
- atomic 線程安全(這里指的讀寫線程的安全);
- atomic 執(zhí)行性能比較低;
- atomic 是默認(rèn)的;
- 非垃圾收集環(huán)境(例如使用retain/release/autorelease)中的原子訪問器會(huì)使用線程鎖,確保其他線程不會(huì)影響到當(dāng)前線程對(duì)該屬性的正確讀寫(getting/setting)。
Example:
@property (copy) NSString *name;
2) nonatomic
- nonatomic 意味著多線程訪問變量(動(dòng)態(tài)類型);
- nonatomic 線程不安全(這里指的讀寫線程的安全);
- nonatomic 執(zhí)行性能較高;
- nonatomic 不是默認(rèn)的,我們需要在屬性修飾中添加
nonatomic關(guān)鍵字; - 當(dāng)兩個(gè)不同的進(jìn)程(線程)訪問同時(shí)訪問該屬性的時(shí)候,可能得到的結(jié)果并不是我們的。
Example:
@property (nonatomic, copy) NSString *name;
解釋說明
假設(shè)有一個(gè)atomic的屬性“name”,其類型是NSString。進(jìn)行以下操作:
- 通過
線程A調(diào)用[self setName:@"A"], - 通過
線程B調(diào)用[self setName:@"B"], - 接著通過
線程C調(diào)用[self name],
不同線程上的所有操作都將串行執(zhí)行,如果一個(gè)線程(假定是線程B)在執(zhí)行setter或getter,其他的線程將排隊(duì)等待。這保證了屬性“name”的讀寫安全。但是如果在線程B執(zhí)行g(shù)etter的前一秒同時(shí)線程D調(diào)用[name release],這個(gè)操作會(huì)導(dǎo)致程序crash。因?yàn)閚ame已被釋放,已經(jīng)沒有g(shù)etter/setter方法了。一個(gè)atomic對(duì)象其讀/寫線程是安全的,但是對(duì)于整個(gè)對(duì)象卻不安全(其他線程可同時(shí)向該對(duì)象發(fā)送任何類型的消息)。開發(fā)者應(yīng)該保證這樣的對(duì)象線程的安全。對(duì)該對(duì)象添加線程鎖。
如果上述的屬性“name”是nonatomic,然后通過線程A、B、C做同于上述例子的操作,同時(shí)線程D同時(shí)調(diào)用[name release]。線程D的操作會(huì)導(dǎo)致不可預(yù)測(cè)的結(jié)果。在atomic例子中,無論線程A、B、C誰先執(zhí)行,線程D都可以并行執(zhí)行。
2.生命周期管理
3) strong(iOS4 = retain)
- 告訴系統(tǒng):把這個(gè)對(duì)象保留在堆上,直到?jīng)]有指針指向它;
- 換句話說:我持有這個(gè)對(duì)象,在我用完它之前你不能將其銷毀(dealloc);
- 只有當(dāng)你需要保留該對(duì)象時(shí)才能使用strong修飾;
- 在ARC下使用strong不用擔(dān)心引用計(jì)數(shù)的問題,ARC會(huì)在你需在需要該對(duì)象時(shí)自動(dòng)將其釋放
Example:
@property (nonatomic, strong) UIViewController *viewController;
4) weak(iOS4 = unsafe_unretained)
- 告訴系統(tǒng):在別人強(qiáng)引用它之前,盡可能的保留;
- 不改變引用計(jì)數(shù);
- assign也是一樣的,不持有也不釋放;
- ‘weak’引用是弱引用,你并沒有持有它;
- 我們一般在使用IBOutlets(UIViewController的childs(子視圖)的時(shí)候使用weak。因?yàn)閏hilds的存在時(shí)長盡可能和其父視圖一樣長。
- 若引用的屬性/對(duì)象,垃圾回收機(jī)制(GC)在回收的時(shí)候,其引用者不會(huì)保護(hù)該對(duì)象。
- weak本質(zhì)上是分配一個(gè)不被持有的屬性,當(dāng)引用者被銷毀(dealloc)時(shí),weak引用的指針會(huì)自動(dòng)被置為nil。
Example:
@property (nonatomic, weak) IBOutlet UIButton *myButton;
解釋說明
假設(shè)有一個(gè)對(duì)象:狗,狗總是想要跑開(dealloc)。
強(qiáng)引用(Strong)就像系在狗脖子上的鏈子。只要這根鏈子一直系在狗脖子上,它就不會(huì)跑開。
如果五個(gè)人都將自己的鏈子系在這只狗的脖子上(該對(duì)象有五個(gè)強(qiáng)引用)。只有這五根鏈子全部解開,狗才能跑開。
弱引用(weak)就像小朋友指著一只狗說:“看,這里有一只狗”。只要這只狗身上仍然有鏈子,只要小朋友仍然可以看到這只狗,那小朋友就能一直指著它。當(dāng)狗脖子上的所有鏈子都解開了,無論多少個(gè)小朋友指著它,它都會(huì)跑開。
只要對(duì)象不在被強(qiáng)引用,那么該對(duì)象將會(huì)被釋放,同時(shí)所有的弱指針都將被置為nil。
如果你想避免循環(huán)引用,那么就用weak來修飾吧。
5) retain
- 釋放舊對(duì)象,并使傳入的新對(duì)象引用計(jì)數(shù)+1;
- retain和strong一樣;
- Apple說如果你用了retain修飾對(duì)象,它將自動(dòng)被轉(zhuǎn)換為Strong;
- 此屬性只能用于NSObject及其子類,而不能用于Core Foundation(因?yàn)槠錄]有使用引用計(jì)數(shù),需要另外使用CFRetain和CFRelease來進(jìn)行CF的內(nèi)存管理)
Example:
@property (nonatomic, retain) NSString *name;
6) assign
- assgin 是默認(rèn)的,不更改引用計(jì)數(shù);
- 一般用于基礎(chǔ)類型的數(shù)據(jù)(NSInteger)和C語言類型數(shù)據(jù)(int,float,double,char,bool)
- assgin 對(duì)象被釋放后指針不會(huì)被置為nil,這會(huì)導(dǎo)致野指針的出現(xiàn)。
Example:
@property (nonatomic, assign) CGFloat viewHeight;
7) unsafe_unretained
- unsafe_unretained就是ARC版本的assign;
- 對(duì)象被釋放后指針不會(huì)被置為nil,這會(huì)導(dǎo)致懸空指針的出現(xiàn)。
Example:
@property (nonatomic, unsafe_unretained) CGFloat viewHeight;
8) copy
- 當(dāng)一個(gè)對(duì)象是可變的時(shí)候需要用到copy,如NSMutableArray、NSMutableDictionary、NSString;
- copy 創(chuàng)建新值,釋放舊值;
- copy和retain類似,返回一個(gè)你需要明確釋放的對(duì)象。
Example:
@property (nonatomic, copy) NSString *name;
9) readonly
- 聲明你的屬性是只讀的,并且告訴編譯器不用自動(dòng)生成setter方法;
- 當(dāng)你嘗試給一個(gè)readonly的屬性賦值時(shí),會(huì)Xcode提示錯(cuò)誤。
Example:
@property (nonatomic, readonly) NSString *name;
10) readwrite
- 編譯器會(huì)自動(dòng)生成setter/getter方法;
- 可以讀、寫;
- readwrite是默認(rèn)的;
Example:
@property (nonatomic, readwrite) NSString *name;