之前面試了幾家公司,都會問到這個基礎的問題,以前,沒有怎么注意,所以答的很混亂,所以查了查網上的資料,特意整理了一份。
常見修飾詞有:assign、weak、strong、retain、copy、nonatomic、atomic、readonly、readwrite
其中部分用在特定的內存管理中:
ARC:assign、weak、strong、copy
MRC:assign、retain、copy、nonatomic、atomic
assign ( ARC/MRC )
1.這個修飾詞是直接賦值的意思 , 整型/浮點型等數據類型都用這個詞修飾 。
2.如果沒有使用 weak、strong、 retain、 copy 等修飾 , 那么默認就是使用 assign 了 ( 它們之間是有你沒我的關系 ,一般的指針變量是strong修飾)。
3.當然其實對象也可以用 assign 修飾 , 只是對象的計數器不會+1 . ( 與 strong 的區別 )
4.如果用來修飾對象屬性 , 那么當對象被銷毀后指針是不會指向 nil 的 . 所以會出現野指針錯誤 ( 與weak的區別 )。
weak ( ARC )(對象)
1.弱指針是針對對象的修飾詞 , 就是說它不能修飾基本數據類型(int float) 。
2.weak 修飾的引用計數器不會+1 , 也就是直接賦值 。
3.弱引用是為打破循環引用而生的,比如在Block中,block在copy的時候,會對內部使用到的對象的引用技術+1,如果使用[self 方法名],那么就會有一個強指針指向self所在的對象的內存地址,對象的引用計數會+1,這樣一來會導致對象所在的內存地址無法被釋放,造成內存泄漏 。
4.它最被人所喜歡的原因是 它所指向的對象如果被銷毀 , 它會指向 nil . 從而不會出現野指針錯誤 。
weak 和 assign的區別
assign與weak,它們都是弱引用聲明類型,但是他們是有區別的。
1.用weak聲明的變量在棧中就會自動清空,賦值為nil。
2.用assign聲明的變量在棧中可能不會自動賦值為nil,就會造成野指針錯誤!
以delegate的聲明為例,在MRC中多delegate聲明使用的是assign,這是為了不造成循環引用,這時,我們需要在-dealloc方法中寫上 self.delegate = nil,以免造成delegate的野指針錯誤。當然,在ARC中,只需要用weak聲明delgate,就會自動釋放了。
strong ( ARC )(對象)
1.直接賦值並且對象的引用計數器 +1 。
2.在 ARC 里替代了 retain 的作用 。
retain ( MRC )
1.release 舊對象( 舊對象計數器 -1 ) , retain 新對象( 新對象計數器 +1 ) , 然后指向新對象 。
2.在set方法里面是這樣的 :
if (_dog != nil) {
[_dog release];
}
_dog = [dog retain];
copy ( ARC/MRC )
1.copy 在 MRC 時是這樣做的 release 舊對象( 舊對象的引用計數器 -1 ) , copy 新對象( 新對象的引用計數器 +1 ) , 然后指向新對象 .(新對象是指最終指向的那個對象,不管深拷貝還是淺拷貝)
- 1.1在set方法里面是這樣的 :
if (_dog != nil) {
[_dog release];
}
_dog = [dog copy];
2.copy 在 ARC 時是這么干的 copy 新對象( 新對象的引用計數器 +1 ) , 然后指向新對象 。
- 2.1在set方法里面是這樣的 :
_dog = [dog copy];
3.使用注意 :
- 3.1 修飾的屬性本身要不可變的。例如 NSMutableArray 采用 copy 修飾 , 在addObject時會出現Crash, 因為NSMutableArray的對象在copy 過后就會變成NSArray。如果需要copy NSMutableArray對象,用:mutablecopy。
- 3.2 對遵守 NSCopying 協議的對象使用 。
nonatomic ( ARC/MRC )
1.不對set方法加同步鎖 。
2.性能好。
3.線程不安全。
atomic ( ARC/MRC )
1.原子屬性就是對生成的 set 方法加互斥鎖 (互斥鎖 是一種同步鎖,
互斥鎖:如果共享數據已經有其他線程加鎖了,線程會進入休眠狀態等待鎖。一旦被訪問的資源被解鎖,則等待資源的線程會被喚醒。
自旋鎖:如果共享數據已經有其他線程加鎖了,線程會以死循環的方式等待鎖,一旦被訪問的資源被解鎖,則等待資源的線程會立即執行。
自旋鎖的效率高於互斥鎖 )
@synchronized(鎖對象) 。
@synchronized(self) { _delegate = delegate;}
2.需要消耗系統資源 。
3.互斥鎖是利用線程同步實現的 , 意在保證同一時間只有一個線程調用 set 方法 。
4.其實還有 get 方法 , 要是同時 set 和 get 一起調用還是會有問題的 . 所以即使用了 atomic 修飾 還是不夠安全 。
nonatomic 和 atomic 的介紹和區別
1. 什么是atomicity(原子性)?
atomicity(原子性):我把原子性理解成線程對屬性的單一執行。
例如,當兩條線程同時執行一個屬性的set方法的時候,如果不具有原子性(也就是聲明屬性時使用了nonatimic),那么就可能出現當A線程正在改寫某屬性值的時候,B線程也許會突然闖入,把尚未修改好的屬性值讀取出來。發生這種情況時,線程讀取到的屬性值肯定不對。
2. 保證atomicity真的就線程安全了嗎?為什么日常聲明都用的是nonatomic呢?
1.保證atomicity並非也是線程安全的,如果需要保證安全,需要跟深層次的線程鎖定機制。
2.使用同步鎖在iOS中開銷比較大,會給程序帶來性能上的問題。
3. 為什么atomicity也不能保證線程安全?
例如:當使用atomic時,仍然可能出現線程錯誤:當線程A進行set操作,這時其他線程的get或者set操作會因為等該操作而等待。當A線程的set操作結束后,B線程進行set操作,然后當A線程需要get操作時,卻獲得了在B線程的值,這就破壞了線程安全,如果有C線程在A線程get操作之前release了該屬性,那么還會導致程序崩潰。所以僅僅使用atomic並不會使得線程安全,我們還是要為線程添加lock來確保線程的安全。
readonly (只讀)
1.讓 Xcode 只生成get方法 。
2.不想把暴露的屬性被人隨便替換時 , 可以使用 。
readwrite (讀寫)(默認)
1.讓 Xcode 生成get/set方法 。
2.不用 readonly 修飾時 , 默認就是 readwrite 。