iOS中屬性修飾符

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è)置屬性的值。

屬性修飾符有以下幾種:

  1. atomic
  2. nonatomic
  3. strong/retain
  4. weak = unsafe_unretained
  5. retain
  6. assign
  7. unsafe_unretained
  8. copy
  9. readonly
  10. readwrite

其中默認(rèn)的修飾符是:

  1. atomic
  2. stong
  3. assign
  4. 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)行以下操作:

  1. 通過線程A調(diào)用[self setName:@"A"]
  2. 通過線程B調(diào)用[self setName:@"B"],
  3. 接著通過線程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;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容