前言
現(xiàn)在iOS 開發(fā)已經(jīng)不再是 mrc 了,現(xiàn)在是 arc 和 swift 的時代,但是內(nèi)存管理一直是個非常重要的問題,對于我們初學者來說,如果只是盲目的開發(fā),不知道管理內(nèi)存的話,會給我們的開發(fā)帶來很大的麻煩。
內(nèi)存管理是程序開發(fā)中很重要的一部分,我們的程序在運行中會消耗內(nèi)存,運行結束之后釋放占用的內(nèi)存。如果在程序運行中只占用內(nèi)存不及時釋放的話,會導致程序的內(nèi)存越來越少,最終導致程序崩潰。所以,作為我們程序員,在開發(fā)的過程中一定要處理好內(nèi)存問題。
首先,我們先了解下內(nèi)存管理中相關的概念:
1.引用計數(shù)
在 ObjC中,創(chuàng)建的對象什么時候會被釋放?
當這個對象沒有被任何變量引用的時候,或者說沒有指針指向的時候,這個對象就會被釋放。
我們怎么才能知道對象有沒有被引用呢?
引用計數(shù):
1.每個對象都會關聯(lián)一個整數(shù),這個整數(shù)就叫做引用計數(shù)器
2.對象每創(chuàng)建一次,其引用計數(shù)就會加1
3.當對象銷毀的時候,其引用計數(shù)減
4.當對象的引用計數(shù)為0的時候,會給對象發(fā)送 dealloc 消息銷毀對象:由于釋放對象會調(diào)用 dealloc 方法,因此要重寫 dealloc 方法來查看對象是否釋放了。
2自動釋放池
從前面我們已經(jīng)知道了,當一個對象不再使用的時候,會被釋放掉,但是有些時候,我們不知道對象什么時候不再使用,不能確定被銷毀的時間。
ObjC給我們提供了 autorelease 的方法來解決這個問題,當給一個對象發(fā)送 autorelease 消息的時候,方法就會在未來的某個時間里給這個對象發(fā)送 release 消息,來釋放該對象。
什么是自動釋放池呢?
自動釋放池就是一個可以容納對象,并且可以自動釋放對象的一個池子,方便了我們對內(nèi)存的管理。
它的原理就是在對象接到autorelease的時候,會被添加到當前的自動釋放池中,當這個自動釋放池銷毀額時候,會給池中所有的對象發(fā)送 release 消息,銷毀對象 。
3 iOS的內(nèi)存管理原則
3.1基本原則
1.當我們通過 new、alloc、copy 方法創(chuàng)建一個對象的時候,它的引用計數(shù)為1,當我們不再使用該對象的時候,應該向對象發(fā)送 release 或者 autorelease 消息來釋放對象。
2.當我們通過其他方法獲得一個對象的時候,如果對象的引用計數(shù)為1且被設置為autorelease,那么就不需要執(zhí)行任何釋放對象的操作;
3.如果你打算取得對象額所有權,就需要保留對象并在操作完成之后釋放,保證相等次數(shù)的 retain 和 release。
其實就是有借必有還
3.2 ARC
在 MRC 時代,我們必須要遵守上面的規(guī)則,如果不遵守的話內(nèi)存問題將會很讓人頭疼,但是到了ARC 的時代,內(nèi)存問題就相對于之前沒那么復雜了,對于初學者來說就能更好的來管理內(nèi)存問題。
iOS 5之后,我們就可以開啟 ARC 模式了,你可以將它理解為一個助手,它會幫我們管理內(nèi)存,不需要我們手動的添加了,它的工作原理就是編譯器在編譯的時候會在代碼中插入合適的 retain 和 release 語句,就相當于在背后幫我們完成了內(nèi)存的管理工作。
注意:
1.如果你的工程是老工程的話。你可以轉換成 ARC,這樣可以方便后期的維護。
2.如果你的工程引用了一些不支持ARC 的庫,可以在Build Phases的Compile Sources將對應的m文件的編譯器參數(shù)配置為-fno-objc-arc
3.3 ARC 的修飾符
ARC 模式下一共有四種修飾符,分別是strong、weak、autoreleasing、unsafe_unretained
strong:強引用,持有所指向對象的所有權,無修飾符的情況下,默認就是 strong,如果想要強制性釋放,將對象置為 nil。
weak:弱引用,不持有所指向對象的所有權,指向的對象內(nèi)存被銷毀之后,引用本身會置為 nil,這樣可以避免野指針。比如我們?yōu)榱吮苊庋h(huán)引用,聲明的時候要用 weak。
autoreleasing:自動釋放對象的引用,一般用于參數(shù)的傳遞。
unsafe_unretained:這個修飾符是在 iOS5之前用的,相當于現(xiàn)在 weak,現(xiàn)在一般都用不到了。
3.4 屬性的內(nèi)存管理
1.assign:直接賦值
assign 一般用來修飾基本數(shù)據(jù)類型,它也可以修飾 OC 對象,但是不推薦這樣寫,因為被 assign 修飾的對象釋放之后,指針還是指向釋放前的內(nèi)存,容易導致程序崩潰。
2.retain
retain 和 strong 一樣,都是用來修飾 OC 對象的
使用 set 方法賦值的時候,實際上是會先保留新值,再釋放舊值,在設置新值,避免新舊值一樣時導致對象被釋放的問題
MRC
- (void)setCount(NSObject*)count {
[count retain];
[_count release];
_count = count;
}
```
ARC
- (void)setCount:(NSObiect *)count {
_count = count;
}
**3.copy**
一般是用來修飾 String、Dict、Array 的,尤其是在內(nèi)容可變的情況下,會深拷貝一份內(nèi)容給屬性,避免可能造成對源內(nèi)容進行改動。
**4.weak**
weak 和 strong 一樣都是用來修飾 OC 對象的,比如常用代理的聲明,Xib 控件的引用都是用的 weak。
**3.5 block 內(nèi)存管理**
iOS 中使用 block 必須要自己管理內(nèi)存,錯誤的內(nèi)存管理將導致循環(huán)引用等內(nèi)存泄漏問題,只用 block 時候要注意以下幾點:
1.當你聲明一個block 時候,要使用 copy 來修飾,不要用 retain 來修飾。
2.block 會對內(nèi)部使用的對象進行強引用,可以給其添加一個弱引用的標記。