OC基礎(六)——記憶體管理
記憶體管理概述
- 記憶體管理
記憶體的作用:儲存資料.
如何將資料儲存到記憶體之中.
宣告1個變數.然後將資料儲存進去.當資料不再被使用的時候,佔用的記憶體空間如何被釋放.
-
記憶體中的五大區域
棧: 區域性變數. 當區域性變數的作用域被執行完畢之後,這個區域性變數就會被系統立即回收.
堆: OC物件.使用C函式申請的空間.
BSS段: 未初始化的全域性變數、靜態變數. 一旦初始化就回收 並轉存到資料段之中.
資料段: 已經初始化的全域性變數、靜態變數. 直到程式結束的時候才會被回收.
程式碼段: 程式碼. 程式結束的時候,系統會自動回收儲存在程式碼段中的資料.棧、BSS段、資料段、程式碼段儲存在它們中的資料的回收,是由系統自動完成的.不需要我們干預.
-
分配在堆區中的OC物件,是肯定需要被回收的.
iPhone 記憶體機制.
40M 警告
45M 警告
120M 閃退.儲存在堆中的OC物件,系統不會自動回收. 直到程式結束的時候才會被回收.
記憶體管理的範圍:
只需要管理儲存在堆中的OC物件的回收.其他區域中的資料的回收是系統自動管理的.-
物件應該什麼時候被回收?
當有人使用這個物件的時候,這個物件就千萬不能回收.
只有在沒有任何人使用這個物件的時候,才可以回收. -
引用計數器
1). 每1個物件都有1個屬性.叫做retainCount.叫做引用計數器. 型別是unsigned long 佔據8個位元組.
引用計數器的作用: 用來記錄當前這個物件有多少個人在使用它.
預設情況下,建立1個物件出來 這個物件的引用計數器的預設值是1.2). 當多1個人使用這個物件的時候.應該先讓這個物件的引用計數器的值+1 代表這個物件多1個人使用.
3). 當這個物件少1個人使用的時候.應該先讓這個物件的引用計數器的值-1 代表這個物件少1個人使用.
4). 當這個物件的引用計數器變為0的時候.代表這個物件無人使用. 這個時候系統就會自動回收這個物件.
-
如何操作引用計數器.
1). 為物件傳送1條retain訊息. 物件的引用計數器就會加1. 當多1個人使用物件的時候才發.
2). 為物件傳送1條release訊息.物件的引用計數器就會減1. 當少1個人使用物件的時候才發.
3). 為物件傳送1條retainCount訊息. 就可以去到物件的引用計數器的值.
就這樣++ -- 當物件的引用計數器變為0的時候,物件就會被系統立即回收.
在物件被回收的時候.會自動呼叫物件的dealloc方法.
-
記憶體管理的分類
MRC: Manual Reference Counting 手動引用計數.手動記憶體管理.
當多1個人使用物件的時候,要求程式設計師手動的傳送retain訊息.少1個人使用的時候程式設計師手動的傳送relase訊息.
2011年之前 iOS5之前
ARC: Automatic Reference Counting 自動引用計數.自動記憶體管理.
系統自動的在合適的地方傳送retain relase訊息.
第一個MRC程式(這個簡單知道就行了)
-
iOS5開始. Xcode4.2開始就支援ARC
Xcode7 預設支援ARC開發.
預設使用的開發方式就是ARC的模式.關閉ARC開啟MRC.
-
當物件的引用計數器變為0的時候,系統會自動回收物件.
在系統回收物件的時候.會自動的呼叫物件的dealloc方法.重寫dealloc方法的規範:
必須要呼叫父類的dealloc方法. 並且要放在最後一句程式碼. -
測試引用計數器.
1). 新建立1個物件,這個物件的引用計數器的值預設是1.
2). 當物件的引用計數器變為0的時候.物件就會被系統立即回收 並自動呼叫dealloc方法.
3). 為物件傳送retain訊息 物件的引用計數器就會+1 為物件傳送release訊息.並不是回收物件.而是讓物件的引用計數器-1
當物件的引用計數器的值變為0的時候.物件才會被系統立即回收.
記憶體管理原則
-
記憶體管理的重點
1). 什麼時候為物件傳送retain訊息.
當多1個人使用這個物件的時候,應該先為這個物件傳送retain訊息.
2). 什麼時候為物件傳送release訊息.
當少1個人使用這個物件的時候.應該為這個物件傳送1條release訊息.
在ARC機制下,retain release dealloc這些方法無法呼叫.
-
記憶體管理的原則
1). 有物件的建立,就要匹配1個release
2). retain的次數和release的次數要匹配.
3). 誰用誰retain. 誰不用誰release.
誰負責retain 誰就負責relase4). 只有在多1個人用的時候才retain 少1個人使用的時候才release
有始有終,有加就有減. 有retain就應該匹配1個release 一定要平衡.
野指標與殭屍物件
-
野指標
C語言中的野指標: 定義1個指標變數.沒有初始化.這個指標變數的值是1個垃圾值,指向1塊隨機的空間.這個指標就叫做野指標.
OC中的野指標: 指標指向的物件已經被回收了.這樣的指標就叫做野指標.
-
物件回收的本質.
記憶體回收的本質:
申請1個變數,實際上就是向系統申請指定位元組數的空間.這些空間系統就不會再分配給別人了.
當變數被回收的時候,代表變數佔用的位元組空間從此以後系統可以分配給別人使用了.
但是位元組空間中儲存的資料還在.回收物件:
所謂的物件的回收,指的是物件佔用的空間可以分配給別人.
當這個物件佔用的空間沒有分配給別人之前 其實物件資料還在. -
殭屍物件
1個已經被釋放的物件,但是這個物件所佔的空間還沒有分配給別人.這樣的物件叫做殭屍物件.我們通過野指標去訪問殭屍物件的時候.有可能沒問題 也有可能有問題.
當殭屍物件佔用的空間還沒有分配給別人的時候.這是可以的.
當殭屍物件佔用的空間分配給了別人使用的時候 就不可以. -
我們認為只要物件稱為了殭屍物件,無論如何 都不允許訪問了.
就希望如果訪問的是殭屍物件,無論如何報錯.殭屍物件的實時檢查機制.可以將這個機制開啟. 開啟之後. 只要訪問的是殭屍物件,無論空間是否分配 就會報錯.
-
為什麼不預設開啟殭屍物件檢測.
一旦開啟殭屍物件檢測 那麼在每訪問1個物件的時候 都會先檢查這個物件是否為1個殭屍物件,
這樣是極其消耗效能的. -
使用野指標訪問殭屍物件會報錯. 如何避免殭屍物件錯誤..
當1個指標稱為野指標以後.將這個指標的值設定nil
當1個指標的值為nil 通過這個指標去呼叫物件的方法(包括使用點語法)的時候.不會報錯. 只是沒有任何反應.
但是如果通過直接訪問屬性 -> 就會報錯. 無法復活1個殭屍物件.
單個物件的記憶體管理
-
記憶體洩露.
指的是1個物件沒有被及時的回收.在該回收的時候而沒有被回收
一直駐留在記憶體中,直到程式結束的時候才回收. -
單個物件的記憶體洩露的情況.
1). 有物件的建立,而沒有對應的relase
2). retain的次數和relase的次數不匹配.
3). 在不適當的時候,為指標賦值為nil
4). 在方法中為傳入的物件進行不適當的retain
-
如何保證單個物件可以被回收
1). 有物件的建立 就必須要匹配1個relase
2). retain次數和release次數一定要匹配.
3). 只有在指標稱為野指標的時候才賦值為nil
4). 在方法中不要隨意的為傳入的物件retain.
多個物件的記憶體管理
-
當屬性是1個OC物件的時候. setter方法的寫法.
將傳進來的物件賦值給當前物件的屬性,代表傳入的物件多了1個人使用,所以我們應該先為這個傳入的物件傳送1條retain訊息 再賦值.
噹噹前物件銷燬的時候.代表屬性指向的物件少1個人使用. 就應該在dealloc中relase
程式碼寫法:
- (void)setCar:(Car *)car { _car = [car retain]; } - (void)dealloc { [_car release]; [super dealloc]; }
當屬性是1個OC物件的時候,setter方法照著上面那樣寫,其實還是有Bug的.
-
當為物件的這個屬性多次賦值的時候.就會發生記憶體洩露.
發生洩露的原因: 當為屬性賦值的時候, 代表舊物件少1個人用.新物件多1個人使用.
應該relase舊的 retain新的.-(void)setCar:(Car *)car { [_car release]; _car = [car retain]; }
@property引數
-
在MRC的開發模式下.1個類的屬性如果是1個OC物件型別的.那麼這個屬性的setter方法就應該按照下面的格式寫.
- (void)setCar:(Car *)car { if(_car != car) { [_car release]; _car = [car retain]; } } 還要重寫dealloc方法. - (void)dealloc { [_car release]; [super delloc]; } 如果屬性的型別不是OC物件型別的.不需要像上面那樣寫. 還是像之前那樣寫就OK了.
-
@property
1). 作用
a. 自動生成私有屬性.
b. 自動生成這個屬性的getter setter方法的宣告.
c. 自動生成這個屬性的getter setter方法的實現.特別播報:
生成的setter方法的實現中,無論是什麼型別的,都是直接賦值. -
@property引數.
1). @property可以帶引數的.
@property(引數1,引數2,引數3......)資料型別 名稱;
2). 介紹一下@property的四組引數.
a. 與多執行緒相關的兩個引數.
atomic、nonatomic.b. 與生成的setter方法的實現相關的引數.
assign、retain.c. 與生成只讀、讀寫相關的引數
readonly readwrited. 是與生成的getter setter方法名字相關的引數.
getter setter -
介紹與多執行緒相關的引數.
atomic: 預設值. 如果寫atomic,這個時候生成的setter方法的程式碼就會被加上一把執行緒安全鎖.
特點: 安全、效率低下.
nonatomic: 如果寫nonatomic 這個時候生成的setter方法的程式碼就不會加執行緒安全鎖.
特點: 不安全,但是效率高.建議: 要效率. 選擇使用nonatomic 在沒有講解多執行緒的知識以前 統統使用nonatomic
-
與生成的setter方法的實現相關的引數.
assign: 預設值 生成的setter方法的實現就是直接賦值.
retain: 生成的setter方法的實現就是標準的MRC記憶體管理程式碼.
也就是. 先判斷新舊物件是否為同1個物件 如果不是 release舊的 retain新的.當屬性的型別是OC物件型別的時候,那麼就使用retain
當屬性的型別是非OC物件的時候,使用assign.千萬注意:
retain引數.只是生成標準的setter方法為標準的MRC記憶體管理程式碼 不會自動的再dealloc中生成relase的程式碼.
所以, 我們還要自己手動的在dealloc中release -
與生成只讀、讀寫的封裝.
readwrite: 預設值.代表同時生成getter setter
readonly: 只會生成getter 不會生成setter -
生成getter、setter方法名稱相關的引數.
預設情況下.@property生成的getter setter方法的名字都是最標準的名字.
其實我們可以通過引數來指定@property生成的方法的名字.getter = getter方法名字
用來指定@property生成的getter方法的名字.setter = setter方法名字
.用來指定@property生成的setter方法的名字. 注意.setter方法是帶引數的 所以要加1個冒號.記住:如果使用getter setter修改了生成的方法的名字.
在使用點語法的時候.編譯器會轉換為呼叫修改後的名字的程式碼.修改生成的getter setter方法名字. 因為預設情況下生成的方法的名字已經是最標準的名字了.
所以.一般情況下不要去改.
1). 無論什麼情況都不要改setter方法的名字. 因為預設情況下生成的名字就已經是最標準的了.
2). 什麼時候修改getter方法的名字.當屬性的型別是1個BOOL型別的時候.就修改這個getter的名字以is開頭 提高程式碼的閱讀性.
------總結-------
與多執行緒相關的引數: 用nonatomic
與生成的setter方法實現相關的引數
屬性的型別是OC物件的時候 使用retain
屬性的型別是非OC物件的時候 使用assign只讀 讀寫.
如果你希望生成的封裝是隻讀封裝 那麼就使用readonly
如果希望讀寫封裝 readwrite1). 無論什麼情況都不要改setter方法的名字. 因為預設情況下生成的名字就已經是最標準的了.
2). 什麼時候修改getter方法的名字.當屬性的型別是1個BOOL型別的時候.就修改這個getter的名字以is開頭 提高程式碼的閱讀性.
------使用引數注意-----
同1組引數只能使用1個.
getter setter可以同時使用.-
引數的順序可以隨意.
@class
當兩個類相互包含的時候. 當Person.h中包含Book.h 而Book.h中又包含Person.h
這個時候,就會出現迴圈引用的問題. 就會造成無限遞迴的問題,而導致無法編譯通過.-
解決方案:
其中一邊不要使用#import引入對方的標頭檔案.
而是使用@class 類名; 來標註這是1個類.這樣子就可以在不引入對方標頭檔案的情況下,告訴編譯器這是1個類.在.m檔案中再#import對方的標頭檔案.就可以使用了.
-
@class與#import的區別
1). #import是將指定的檔案的內容拷貝到寫指令的地方.
2). @class 並不會拷貝任何內容. 只是告訴編譯器,這是1個類,這樣編譯器在編譯的時候才可以知道這是1個類.
迴圈retain
當兩個物件相互引用的時候.
A物件的屬性是B物件 B物件的屬性是A物件.
這個時候 如果兩邊都使用retain 那麼就會發生記憶體洩露.解決方案: 1端使用retain 另外1端使用assign 使用assign的那1端在dealloc中不再需要release了.
自動釋放池(瞭解)
自動釋放池的原理.
存入到自動釋放池中的物件,在自動釋放池被銷燬的時候.會自動呼叫儲存在該自動釋放池中的所有物件的release方法.
可以解決的問題:
將建立的物件,存入到自動釋放池之中. 就不再需要手動的relase這個物件了.
因為池子銷燬的時候 就會自動的呼叫池中所有的物件的relase。
自動釋放池的好處: 將建立的物件儲存到自動釋放池中,不需要再寫release
如何建立自動釋放池.
@autoreleasepool
{
}
這對大括弧代表這個自動釋放池的範圍.
如何將物件儲存到自動釋放池之中
在自動釋放池之中呼叫物件的autorelease方法.就會將這個物件存入到當前自動釋放池之中.
這個autorealse方法返回的是物件本身. 所以,我們可以這麼寫
@autoreleasepool
{
Person *p1 = [[[Person alloc] init] autorelease];
}
這個時候,當這個自動釋放池執行完畢之後,就會立即為這個自動釋放池中的物件傳送1條release訊息.
目前為止,我們感受到得autorelase的好處:
建立物件,呼叫物件的autorelase方法 將這個物件存入到當前的自動釋放池之中.
我們就不需要再去relase 因為自動釋放池銷燬的時候 就會自動的呼叫池中所有物件的relase
使用注意
1). 只有在自動釋放池中呼叫了物件的autorelease方法,這個物件才會被儲存到這個自動釋放池之中.
如果只是將物件的建立程式碼寫在自動釋放之中,而沒有呼叫物件的autorelease方法.是不會將這個物件儲存到這個自動釋放池之中的.
2). 物件的建立可以在自動釋放池的外面,在自動釋放池之中,呼叫物件的autorelease方法,就可以將這個物件儲存到這個自動釋放池之中.
3). 當自動釋放池結束的時候.僅僅是對儲存在自動釋放池中的物件傳送1條release訊息 而不是銷燬物件.
4). 如果在自動釋放池中,呼叫同1個物件的autorelease方法多次.就會將物件儲存多次到自動釋放池之中.
在自動釋放池結束的時候.會為物件傳送多條release訊息.那麼這個是就會出現殭屍物件錯誤.
所以,1個自動釋放池之中,只autorelease1次,只將這個物件放1次, 否則就會出現野指標錯誤.
5). 如果在自動釋放池中,呼叫了儲存到自動釋放中的物件的release方法.
在自動釋放池結束的時候,還會再呼叫物件的release方法.
這個時候就有有可能會造成野指標操作.
也可以呼叫儲存在自動釋放池中的物件的retain方法.
6). 將物件儲存到自動釋放池,並不會使物件的引用計數器+1
所以其好處就是:建立物件將物件儲存在自動釋放池,就不需要在寫個release了.
7). 自動釋放池可以巢狀.
呼叫物件的autorelease方法,會講物件加入到當前自動釋放池之中
只有在當前自動釋放池結束的時候才會像物件傳送release訊息.
autorelease的規範.
0). 建立物件,將物件儲存到自動釋放池之中. 就不需要再去手動的realse。
1). 類方法的第1個規範:
一般情況下,要求提供與自定義構造方法相同功能的類方法.這樣可以快速的建立1個物件.
2). 我們一般情況下,寫1個類. 會為我們的類寫1個同名的類方法,用來讓外界呼叫類方法來快速的得到1個物件.
規範:使用類方法建立的物件,要求這個物件在方法中就已經被autorelease過了.
這樣,我們只要在自動釋放池中, 呼叫類方法來建立物件, 那麼建立的物件就會被自動的加入到自動釋放中.
提供1個類方法來快速的得到1個物件.
規範
a. 這個類方法以類名開頭. 如果沒有引數就直接是類名 如果有引數就是 類名WithXX:
b. 使用類方法得到的物件,要求這個物件就已經被autorelease過了.
-(instancetype)person{ return [[[self alloc] init] autorelease]; }
這樣,我們直接呼叫類方法.就可以得到1個已經被autorelease過的物件.
@autoreleasepool
{
Person *p1 = [Person person];
//這個p1物件已經被autorelase過了.不需要再呼叫autorelase
//這個p1物件就被儲存到當前自動釋放池之中.
}//當自動釋放池結束.就會為儲存在其中的p1物件傳送release訊息.
實際上Apple的框架中的類也是遵守這個規範的.
通過類方法建立的物件都是已經被autorelease過的了.
所以,我們也要遵守這個規範. 類方法返回的物件也要被autorealse過.
以後,我們凡事建立物件是呼叫類方法建立的物件 這個物件已經是被autorelease過的了.
arc機制概述
什麼是ARC
Automatic Reference Counting,自動引用計數. 即ARC.
顧名思義:系統自動的幫助我們去計算物件的引用計數器的值,
可以說是WWDC2011和iOS5引入的最大的變革和最激動人心的變化.
ARC是新的LLVM3.0
編譯器的一項特性,使用ARC,可以說一舉解決了廣大iOS開著所憎恨的手動管理記憶體的麻煩.
在程式中使用ARC非常簡單,只需要像往常那樣編寫程式碼.
只不過永遠不要寫retain、release、autorelease
永遠要手動的呼叫dealloc
這三個關鍵字就好,這是ARC的最基本的原則.
當ARC開啟時, 編譯器會自動的在合適的地方插入retain、release、autorelase
程式碼.
編譯器自動為物件做引用計數. 而作為開發者,完全不需要擔心編譯器會做錯(除非開發者自己錯用了ARC).
需要特別注意的是: ARC是編譯器機制. 在編譯器編譯程式碼的時候,會在適時的位置加入retain、release和autorealse程式碼.
ARC機制下,物件何時被釋放
本質: 物件的引用計數器為0的時候,自動釋放.
表象: 只要沒有強指標指向這個物件,這個物件就會立即回收.
強指標與弱指標.
強指標: 預設情況下,我們宣告1個指標 這個指標就是1個強指標.
我們也可以使用__strong來顯示的宣告這是1個強指標.
Person *p1; 這是1個強指標. 指標預設情況下都是1個強指標.__strong Person *p2;
這也是1個強指標.使用__strong
來顯示的宣告強指標.
弱指標: 使用__weak標識的指標就叫做弱指標.
無論是強指標還是弱指標,都是指標,都可以用來儲存地址,這1點沒有任何區別 。
都可以通過這個指標訪問物件的成員.
唯一的區別就是在ARC模式下.他們用來作為回收物件的基準.
如果1個物件沒有任何強型別的指標指向這個物件的時候,物件就會被立即自動釋放
確認程式是否開啟ARC機制.
1).預設情況下,Xcode開啟ARC機制.
2).ARC機制下,不允許呼叫retain、relase、retainCount、autorelease方法.
3).在dealloc中 不允許[super dealloc];
演示第1個ARC案例
int main(int argc, const char * argv[])
{
@autoreleasepool
{
Person *p1 = [Person new];//p1是1個強指標.
//因為我們說過,每1個指標變數預設情況下都是1個強指標變數.
NSLog(@"------");
}//當執行到這裡的時候.p1指標被回收,那麼Person物件就沒有任何
//強指標指向它了. 物件就在這被回收.
return 0;
}
第一個arc程式
ARC下的單個物件的記憶體管理.
在ARC的機制下: 當1個物件沒有任何的強指標指向它的時候 這個物件就會被立即回收.
1). 當指向物件的所有的強指標被回收的時候,物件就會被立即回收.
int main(int argc, const char * argv[])
{
@autoreleasepool
{
Person *p1 = [Person new];//p1是1個強指標.
Person *p2 = p1;//p2也是個強指標.p1和p2都指向Person物件.
//因為我們說過,每1個指標變數預設情況下都是1個強指標變數.
NSLog(@"------");
}//當執行到這裡的時候.p1指標被回收,p2指標也被回收.那麼Person物件就沒有任何
//強指標指向它了. 物件就在這被回收.
return 0;
}
2).將所有指向物件的強指標賦值為nil的時候.物件就會被立即回收.
int main(int argc, const char * argv[])
{
@autoreleasepool
{
Person *p1 = [Person new];//p1是1個強指標.
//因為我們說過,每1個指標變數預設情況下都是1個強指標變數.
p1 = nil;//當執行到這句話的時候.p1賦值為nil.
//p1指標不再執行Person物件.
//Person物件沒有被任何的指標所指向,所以.Person物件在這裡被釋放.
NSLog(@"------");
}
return 0;
}
這兩種情況就叫做沒有任何強指標指向物件.
1). 指向物件的所有強指標被回收掉
2). 指向物件的所有的強指標賦值為nil
強指標與弱指標.
1). 強指標與弱指標的宣告.
預設情況下,所有的指標都是強型別的,也就是說我們之前宣告的指標變數都是強類型別的
p1指標是強型別的,因為預設情況下指標都是強型別的.
Person *p1 = [[Person alloc] init];
不過我們可以使用__strong來顯示的標識指標是強型別指標.
__strong Person *p2 = [Person new];
這個時候p2指標型別是強指標型別的.其實寫不寫__strong都是強型別的指標.
指標型別也可以是弱指標型別.
使用__weak標識指標的型別是弱型別指標.
__weak Person *p3 = p2;
這個時候,p3指標就是1個弱型別的指標. p3弱指標也指向p2指標指向的物件.
在操作物件的時候,通過強指標或者弱指標都可以操作,沒有任何區別.
2). ARC模式下的物件回收標準
ARC機制下釋放1個物件的標準是: 沒有任何強指標指向物件的時候,物件就會被釋放.
如果這個時候有弱指標指向,也會被釋放.
int main(int argc, const char * argv[])
{
@autoreleasepool
{
//使用strong來標識p1指標是強型別的,其實不寫strong也是強型別的.
__strong Person *p1 = [[Person alloc] init];
//使用__weak標識指標p2的型別是弱型別指標.
__weak Person *p2 = p1;
//這個時候,p2指標和p1指標都指向Person物件.
//這個時候如果設定p1的值為nil
p1 = nil;
//這個時候Person物件只有被1個弱指標p2指向,沒有任何強指標指向
//所以Person物件在這裡被回收.
}
return 0;
}
3).最重要的1點:不能建立物件用1個弱指標儲存這個物件的指標.
這樣的話,剛建立出來的物件,就沒有任何強指標指向,建立出來就會被回收.
int main(int argc, const char * argv[])
{
@autoreleasepool
{
//建立1個物件,將這個物件的地址賦值給1個弱指標
//後果就是建立出來的這個物件沒有被任何強指標指向.
//剛建立出來就會被釋放.
__weak Person *p1 = [[Person alloc] init];
}
return 0;
}
4). 在ARC機制下. 當物件被回收的時候. 原來指向這個物件的弱指標會被自動設定為nil
arc機制下的多個物件的記憶體管理
ARC機制下的物件的回收的標準: 當沒有任何強型別的指標指向物件的時候,這個物件就會被立即回收.
強型別指標 弱型別指標.
-
什麼情況下叫做物件沒有強指標向指向.
1). 指向物件的強指標被回收.
2). 指向物件的強指標被賦值為nil
-
在ARC的機制下,@property引數不能使用retain
因為retain代表生成的setter方法是MRC的標準的記憶體管理程式碼.
而我們在ARC的機制下 不需要這些程式碼.所以,在ARC機制下的setter方法 什麼都不需要做.直接賦值就可以了.
-
ARC機制下,我們關注的重點.
當1個類的屬性是1個OC物件的時候.這個屬性應該宣告為強型別的還是弱型別的.
很明顯,應該宣告為1個強型別的.問題來了?
如何控制@property生成的私有屬性,是1個強型別的還是1個弱型別的呢?
使用引數, strong和weak
@property(nonatomic,strong)Car *car;
代表生成的私有屬性_car 是1個強型別的.@property(nonatomic,weak)Car *car;
代表生成的私有屬性_car 是1個弱型別的.如果不寫,預設是strong.
-
使用建議.
1). 在ARC機制下.如果屬性的型別是OC物件型別的.絕大多數場景下使用strong
2). 在ARC機制下.如果屬性的型別不是OC物件型別的.使用assign3). strong和weak都是應用在屬性的型別是OC物件的時候. 屬性的型別不是OC物件的時候就使用assign.
在ARC機制下,將MRC下的retain換位strong
@property(nonatomic,strong)Car *car;
做的事情:
1). 生成私有屬性.並且這個私有屬性是strong
2). 生成getter setter方法的宣告
3). 生成getter setter方法的宣告setter的實現:直接賦值.
ARC 迴圈引用
在ARC機制下.當兩個物件相互引用的時候.如果兩邊都使用strong 那麼就會先記憶體洩露.
解決方案: 1端使用strong 1端使用weak
@property 引數總結
開發程式分為ARC和MRC
-
與多執行緒相關的引數.
atomic : 預設值 安全,但是效率低下.
nonatomic: 不安全,但是效率高.無論在ARC還是在MRC都可以使用.
使用建議: 無論是ARC還是MRC 都使用nonatomic -
retain:
只能用在MRC的模式下.代表生成的setter方法是標準的記憶體管理程式碼.
當屬性的型別是OC物件的時候.絕大多數情況下使用retain. 只有在出現了迴圈引用的時候1邊retain 1邊assign assign:
在ARC和MRC的模式下都可以使用assign.
當屬性的型別是非OC物件的時候 使用assign.strong:
只能使用在ARC機制下. 當屬性的型別是OC物件型別的時候,絕大多數情況下使用strong]
只有出現了迴圈引用的時候, 1端strong 1端weak-
weak:
只能使用在ARC機制下. 當屬性的型別是OC物件的時候. 只有出現了迴圈引用的時候, 1端strong 1端weak
-
readonly readwrite
無論是ARC還是MRC 都可以使用.
setter getter 無論在ARC下還是在MRC下都可以改.
在ARC機制下.原來使用retain的用strong
出現迴圈引用的時候. MRC: 1邊retain 1邊assign ARC: 1邊strong 1邊weak
MRC與ARC的相容
-
有可能會遇到的問題.
程式使用的是ARC機制開發的,但是其中的某些類使用的是MRC.
使用命令. ` -fno-objc-arc
補充
- ARC機制和垃圾回收機制的區別.
GC: 程式在執行的期間,有1個東西叫做垃圾回收器.不斷的掃描堆中的物件是否無人使用.
Person *p1 = [Person new];
p1 = nil;
ARC: 不是執行時. 在編譯的時候就在合適的地方插入retain......
插入的程式碼足以讓物件無人使用的時候 引用計數器為0
相關文章
- OC記憶體管理記憶體
- 什麼是記憶體管理?其最主要作用?OC記憶體管理機制?記憶體
- 【重溫基礎】22.記憶體管理記憶體
- OC記憶體管理--物件的生成與銷燬記憶體物件
- 【Java基礎】實體記憶體&虛擬記憶體Java記憶體
- object-c(oc)記憶體管理機制詳解Object記憶體
- .NET基礎拾遺(1):型別語法基礎和記憶體管理基礎型別記憶體
- OC物件記憶體佈局物件記憶體
- java基礎-記憶體分配Java記憶體
- Java基礎:記憶體模型Java記憶體模型
- Java記憶體模型_基礎Java記憶體模型
- 記憶體管理 記憶體管理概述記憶體
- [Java基礎]記憶體洩漏和記憶體溢位Java記憶體溢位
- Java基礎知識_記憶體Java記憶體
- Java記憶體模型的基礎Java記憶體模型
- node記憶體基礎知識記憶體
- 自動共享記憶體管理 自動記憶體管理 手工記憶體管理記憶體
- linux記憶體管理(六)- 核心新struct - folioLinux記憶體Struct
- 記憶體管理篇——實體記憶體的管理記憶體
- java基礎:記憶體分配機制Java記憶體
- C語言記憶體地址基礎C語言記憶體
- Objective-C 基礎教程第九章,記憶體管理Object記憶體
- 【Java基礎】函式引數為物件時的記憶體管理Java函式物件記憶體
- 【記憶體管理】記憶體佈局記憶體
- OC UIImage基礎UI
- OC UIView基礎UIView
- 記憶體管理記憶體
- 記憶體管理兩部曲之實體記憶體管理記憶體
- Java 併發基礎之記憶體模型Java記憶體模型
- Java記憶體模型深度解析:基礎部分Java記憶體模型
- Go:記憶體管理與記憶體清理Go記憶體
- Java的記憶體 -JVM 記憶體管理Java記憶體JVM
- java基礎(一):談談java記憶體管理與垃圾回收機制Java記憶體
- Aerospike的bin記憶體管理--即列記憶體管理ROS記憶體
- 【基礎篇記憶體結構】oracle10g記憶體結構(一)記憶體Oracle
- ORACLE 記憶體管理 之六 SGA Multiple Block Sizes,Large PoolOracle記憶體BloC
- 記憶體管理兩部曲之虛擬記憶體管理記憶體
- 【記憶體管理】Oracle AMM自動記憶體管理詳解記憶體Oracle