iOS記憶體管理 ARC

2021-06-20 07:29:57 字數 4320 閱讀 7842

arc是在編譯的時候插入**來確信讓物件能夠按需要來存在。arc同樣是以引用計數為基礎。你可以選擇在以檔案或者專案為單位不使用arc。

但是建議盡量最好使用arc,首先,編譯器為你做記憶體管理往往比你自己要更優秀,其次,arc導致的效率損失在ui面前基本可以忽略不計。

arc有以下強制規則:

1. 你不能顯示的呼叫dealloc,實現或呼叫retain,release,retaincount,autorelease。

你可以實現自己的dealloc,目的是為了把**設定為空,或者編譯的時候沒有用到arc的**。

2. 不能使用nsallocateobject 和 nsdeallocateobject

3. 不能在c結構體中使用物件指標 ---原因

4. 不能直接轉換id 和 void *

5. 不能使用nsautoreleasepool,被更有效率的@autoreleasepool取代了。

6. 不能直接使用以new開頭的accessor,意味著不能使用以new開頭的屬性,除非你指定乙個不同的名字。如下:

//won't work

@property

nsstring

*newtitle;

//works

@property

(getter

= thenewtitle) nsstring *newtitle;

arc引入了新的關於變數生命週期的限定詞。

__strong 預設的限定符,只要有強指標指向物件,就可以一直存活

__weak  指定乙個引用,這個引用不能保持這個引用的物件存活,沒有強物件指向它的話,弱引用就會被設定為nil

__unsafe_unretained 這個引用不能保持這個引用的物件存活,沒有強物件指向它的話,弱引用就不會被設定為nil,如果它指向的物件釋放了的話,這個指標就成為懸掛指標。

__autoreleasing 用來代表通過引用傳遞並且在返回時自動釋放的引數。

必須正確的使用這些限定符。

nsstring

* __weak

string = [[nsstring alloc] initwithformat:

@"first name: %@"

, [self

firstname]];

nslog(

@"string: %@"

, string);

這個weak使用就是不恰當的,因為沒有任何強指標指向string,string立即就會被釋放了。

棧變數都被初始化為nil。

你需要注意通過引用傳遞的物件。

nserror

*error;

bool

ok = [

myobject

performoperationwitherror:&

error];

-(bool

)performoperationwitherror:(

nserror

* __autoreleasing

*)error;

這個呼叫實際的**是:

nserror

* __strong

error;

nserror

* __autoreleasing

tmp = 

error

;bool

ok = [

myobject

performoperationwitherror:&

tmp];

error = tmp;

因為形式引數是__autorelease和實際引數是__strong,所以編譯器會建立臨時變數。

arc需要在你的init方法中

把[super init]的返回值賦給你的self

self

= [super

init

];if

(self)

struct mystruct

因為x預設是強型別,編譯器不能安全地合成所有以使其正常工作所需的**。比如你把乙個指向該結構的指標傳遞給別的函式,結構體裡面的id必須在結構被free掉之前釋放,但是編譯器不能可靠的做到這些。因此在arc中不能在結構體中使用強物件。可以使用以下解決方案:

1. 使用objective-c objects 代替結構體,這是最好的方式

2  使用void*替代。

3. 使用_unsafe_unretained限定符來比標示物件引用

struct mystruct

當然這可能是有問題的,是不安全的,如果該物件能從指標下被釋放。但是它對那些像字串常量這樣永遠不能改變的東西是非常有用的。

管理 toll-free轉換

在許多cocoa應用中,需要用到core foundation型別的物件。編譯器不能自動管理core foundation物件,需要呼叫cfretain和cfrelease類似的core foundation記憶體管理規則。

當你需要轉換objective c和core foundation物件時,需要使用cast函式或者core foundation的巨集顯示的告訴編譯器你們之間的語義關係。

__bridge 轉換objective c和core foundation之間的指標,不轉移擁有關係。

__bridge_retained 或者cfbridgingretain轉換乙個objective c指標到core foundation 指標並且轉移擁有關係。你需要自己釋放物件的關係。

__bridge_transfer 或者cfbridgingrelease將乙個非objective指標轉換為objective c的指標並且轉移關係到arc,不需要自己釋放物件的關係

比如:以前的**

- (void

)logfirstnameofperson:(abrecordref)person

在arc中轉化為以下**。

- (void

)logfirstnameofperson:(abrecordref)person

使用生命週期限定符來避免強引用迴圈

典型的是在父子繼承層次中,父類需要引用了子類,子類同時也用到了父類,需要把父類中定義為strong,而子類中定義為weak。其他一些情況就比較難以琢磨,特別是呼叫了block物件。

在mrr中,__block id x 不增加x的引用計數,而在arc中是增加引用計數的。為了在arc中獲得在mrr中同樣的行為,需要使用__unsafe_unretain __block id x;但是這又是危險的且不鼓勵的。更好的選擇是使用__weak 或者設定把__block id的值設定為nil來跳出retain迴圈。

以下**片段闡述了這個觀點。

最原始的**是這樣的。

myviewcontroller

*mycontroller = [[myviewcontroller alloc] init...];

mycontroller.completionhandler =  ^(nsinteger result) ; [

self

presentviewcontroller:mycontroller animated:

yescompletion:^];

可以定義為block,並且在block裡面設定為nil

myviewcontroller

* __block

mycontroller = [[myviewcontroller alloc] init...];

mycontroller.completionhandler =  ^(nsinteger result) ;

同樣可以定義乙個臨時的weak變數。

myviewcontroller *mycontroller = [[myviewcontroller alloc] init...];

myviewcontroller * 

__weak

weakmyviewcontroller = mycontroller;

mycontroller.completionhandler =  ^(nsinteger result) ;

對於特殊的引用迴圈,你需要這樣使用。

myviewcontroller *mycontroller = [[myviewcontroller alloc] init...];

myviewcontroller * 

__weak

weakmycontroller = mycontroller;

mycontroller.completionhandler =  ^(nsinteger result)  

else};

IOS基礎之 十一 記憶體管理 ARC

1.set 方法記憶體管理的相關引數 retain release舊值,retain新值 值適用於oc物件 assign 直接賦值 set方法預設,適用於非oc物件型別,即基本資料型別,也包括列舉和結構體 copy release 舊值,copy 新值 nsstring 2.是否生成set方法 re...

iOS非ARC記憶體管理摘要 實踐型

關於ios記憶體管理。在開發過程中,記憶體管理很重要,我簡單說明一下。1.正確用法 uiview v uiview alloc init 分配後引用計數為1 self.view addsubview v 這兒引用計數加1,為2 v release 這兒引用計數為1 最後系統在 self.view的時...

ARC 記憶體管理見解

arc就是自動引用計數,在arc之前,我們都是通過手動管理引用計數的,也就是手動使用release和retain來是引用計數減1或者加1,arc其實還是使用release和retain,只不過系統幫你完成而成。clang語1言擴充套件很有強的類函式巨集,可以使用以下 宣告編譯時支援arc而檔案 不支...