一:@property 後面能夠有哪些修飾符?c++
1:線程安全的:面試
atomic,nonatomic數組
2:訪問權限的安全
readonly,readwrite多線程
3:內存管理(ARC)併發
assign, copy, strong,weak,函數
4: 內存管理(MRC)性能
assign,retain,copy學習
ARC 下,不顯式指定任何屬性關鍵字時,默認的關鍵字都有哪些?atom
基本數據: atomic,readwrite,assign
普通的 OC 對象: atomic,readwrite,strong
二、 readwrite,readonly,assign,retain,copy,nonatomic,atomic,strong,weak屬性的做用分別是什麼。
關鍵字 | 註釋 |
---|---|
readwrite | 此標記說明屬性會被當成讀寫的,這也是默認屬性。 |
readonly | 此標記說明屬性只能夠讀,也就是不能設置,能夠獲取。 |
assign | 不會使引用計數加1,也就是直接賦值。 |
retain | 會使引用計數加1。 |
copy | 創建一個索引計數爲1的對象,在賦值時使用傳入值的一份拷貝。 |
nonatomic | 非原子性訪問,多線程併發訪問會提升性能。 |
atomic | 原子性訪問。 |
strong | 打開ARC時纔會使用,至關於retain。 |
weak | 打開ARC時纔會使用,至關於assign,能夠把對應的指針變量置爲nil。 |
開發過程當中,setter和getter方法到處都在使用,若是使用atomic修飾,setter和getter方法內部會作不少多線程安全的操做,會很佔用系統資源,下降系統性能。
因此在日常開發中原子性(線程安全)通常設置爲nonatomic,只有在須要安全的地方atomic
說atomic與nonatomic的本質區別其實也就是在setter方法上的操做不一樣:
nonatomic的實現:
- (void)setCurrentImage:(UIImage *)currentImage
{
if (_currentImage != currentImage) {
[_currentImage release];
_currentImage = [currentImage retain];
// do something
}
}
- (UIImage *)currentImage
{
return _currentImage;
}
atomic的實現:
- (void)setCurrentImage:(UIImage *)currentImage
{
@synchronized(self) {
if (_currentImage != currentImage) {
[_currentImage release];
_currentImage = [currentImage retain];
// do something
}
}
}
- (UIImage *)currentImage
{
@synchronized(self) {
return _currentImage;
}
}
四:讀寫訪問權限
讀寫性的控制(readonly,readwrite,setter,getter)
readonly:只讀屬性,告訴編譯器之聲明getter方法,而沒有setter(只能讀取值,不能被賦值)
readwrite:讀寫屬性,告訴編譯器,既聲明setter又聲明getter方法,readwrite是屬性讀寫性控制的默認修飾詞
五:內存權限。
1:weak和assign的區別-正確使用weak、assign
不多有人知道weak表實際上是一個hash(哈希)表,Key是所指對象的地址,Value是weak指針的地址數組。更多人的人只是知道weak是弱引用,所引用對象的計數器不會加一,並在引用對象被釋放的時候自動被設置爲nil。一般用於解決循環引用問題。但如今單知道這些已經不足以應對面試了,好多公司會問weak的原理。weak的原理是什麼呢?下面就分析一下weak的工做原理(只是本身對這個問題好奇,學習過程當中的筆記,但願對讀者也有所幫助)。
weak 實現原理的歸納
Runtime維護了一個weak表,用於存儲指向某個對象的全部weak指針。weak表實際上是一個hash(哈希)表,Key是所指對象的地址,Value是weak指針的地址(這個地址的值是所指對象的地址)數組。
weak 的實現原理能夠歸納一下三步:
一、初始化時:runtime會調用objc_initWeak函數,初始化一個新的weak指針指向對象的地址。
二、添加引用時:objc_initWeak函數會調用 objc_storeWeak() 函數, objc_storeWeak() 的做用是更新指針指向,建立對應的弱引用表。
三、釋放時,調用clearDeallocating函數。clearDeallocating函數首先根據對象地址獲取全部weak指針地址的數組,而後遍歷這個數組把其中的數據設爲nil,最後把這個entry從weak表中刪除,最後清理對象的記錄。
6.1:區別
a.修飾變量類型的區別
weak 只能夠修飾對象。若是修飾基本數據類型,編譯器會報錯-「Property with ‘weak’ attribute must be of object type」。
assign 可修飾對象,和基本數據類型。當須要修飾對象類型時,MRC時代使用unsafe_unretained。固然,unsafe_unretained也可能產生野指針,因此它名字是"unsafe_」。
b.是否產生野指針的區別
weak 不會產生野指針問題。由於weak修飾的對象釋放後(引用計數器值爲0),指針會自動被置nil,以後再向該對象發消息也不會崩潰。 weak是安全的。
assign 若是修飾對象,會產生野指針問題;若是修飾基本數據類型則是安全的。修飾的對象釋放後,指針不會自動被置空,此時向對象發消息會崩潰。
c、類似
均可以修飾對象類型,可是assign修飾對象會存在問題。
d、總結
assign 適用於基本數據類型如int,float,struct等值類型,不適用於引用類型。由於值類型會被放入棧中,遵循先進後出原則,由系統負責管理棧內存。而引用類型會被放入堆中,須要咱們本身手動管理內存或經過ARC管理。
weak 適用於delegate和block等引用類型,不會致使野指針問題,也不會循環引用,很是安全。
6.2:copy
由於父類指針能夠指向子類對象,使用 copy 的目的是爲了讓本對象的屬性不受外界影響,使用 copy 不管給我傳入是一個可變對象仍是不可對象,我自己持有的就是一個不可變的副本.
若是咱們使用是 strong,那麼這個屬性就有可能指向一個可變對象,若是這個可變對象在外部被修改了,那麼會影響該屬性
c:深淺copy
七:block中copy
我的理解:默認狀況下,block會存檔在棧中(棧是吃了吐),因此block會在函數調用結束被銷燬,在調用會報空指針異常,若是用copy修飾的話,可使其保存在堆區(堆是吃了拉) ,它的生命週期會隨着對象的銷燬而結束的。只要對象不銷燬,咱們就能夠調用在堆中的block。
在瞭解block爲何要用copy以前,咱們要先了解block的三種類型
一 NSGlobalBlock:全局的靜態block 沒有訪問外部變量 你的block類型就是這種類型(也就是說你的block沒有調用其餘外部變量)
二 NSStackBlock:保存在棧中的block,沒有用copy去修飾而且訪問了外部變量,你的block類型就是這種類型,會在函數調用結束被銷燬 (須要在MRC)
三 NSMallocBlock 保存在堆中的block 此類型blcok是用copy修飾出來的block 它會隨着對象的銷燬而銷燬,只要對象不銷燬,咱們就能夠調用的到在堆中的block。
2.1:首先,咱們要明確一點,爲何要用copy修飾,這是由於在MRC時期,做爲全局變量的block在初始化時是被存放在靜態區的,這樣在使用時若是block內有調用外部變量,那麼block沒法保留其內存,在初始化的做用域內使用並不會有什麼影響,但一但出了block的初始化做用域,就會引發崩潰,使用copy能夠將block的內存推入堆中,這樣讓其擁有保存調用的外部變量的內存的能力。
2.2:(將block存入堆區帶來的一個問題,self會持有block的引用,那麼在block裏使用self會致使循環引用,這也是爲何在MRC和ARC時期要分別用__block和__weak來修飾self的緣由)
既然使用copy的緣由是爲了讓Block在初始化做用域外進行正常訪問外部變量,那咱們就來看使用strong能不能達到這種效果。
3:外部使用了weakSelf,裏面使用strongSelf卻不會形成循環,究其緣由就是由於weakSelf是block截獲的屬性,而strongSelf是一個局部變量會在「函數」執行完釋放。
是爲了保證block執行完畢以前self不會被釋放,執行完畢的時候再釋放。這時候會發現爲何在block外邊使用了__weak修飾self,裏面使用__strong修飾weakSelf的時候不會發生循環引用?!
4.1:__weak
自己是能夠避免循環引用的問題的,可是其會致使外部對象釋放了以後,block 內部也訪問不到這個對象的問題,咱們能夠經過在 block 內部聲明一個 __strong
的變量來指向 weakObj,使外部對象既能在 block 內部保持住,又能避免循環引用的問題。
4.2:__block
自己沒法避免循環引用的問題,可是咱們能夠經過在 block 內部手動把 blockObj 賦值爲 nil 的方式來避免循環引用的問題。
另一點就是 __block
修飾的變量在 block 內外都是惟一的,要注意這個特性可能帶來的隱患。可是__block
有一點:這只是限制在ARC環境下。在非arc下,__block是能夠避免引用循環的/
4.3:另外,MRC中__block是不會引發retain;但在ARC中__block則會引發retain。因此ARC中應該使用__weak。
5:爲何使用weakSelf
經過 clang -rewrite-objc 源代碼文件名 將代碼轉爲c++代碼(實質是c代碼),能夠看到block是一個結構體,它會將全局變量(self)保存爲一個屬性(是__strong的),而self強引用了block這會形成循環 引用。因此須要使用__weak修飾的weakSelf。
6: MRC使用了retain修飾的block崩潰掉了,當將MRC切換回ARC,而且把修飾符換爲strong時,並無發生崩潰,說明該block被推入了堆,擁有了保存外部變量內存的能力。