Objective-C的內存管理實質上就是引用計數(shù)告私。
從前是手動引用計數(shù)(MRC)馁龟,現(xiàn)在是自動引用計數(shù)(ARC)蹋盆。
所謂ARC俭令,就是讓編譯器來進行內存管理后德,現(xiàn)在Xcode默認ARC為有效狀態(tài)。
引用計數(shù):
Objective中抄腔,生成對象時引用計數(shù)為1瓢湃,持有對象引用計數(shù)加一,釋放對象引用計數(shù)減一赫蛇,當對象引用計數(shù)為0時則釋放對象绵患。
在ARC下我們不必關心引用計數(shù)這個概念。但是在MRC下必須清晰引用計數(shù)悟耘,而且要牢記:自己生成的對象自己持有落蝙,非自己生成的對象自己也能持有,不再需要自己持有的對象要釋放暂幼,非自己持有的對象不能釋放筏勒。下面詳細說明:
MRC下:
拿數(shù)組來說,可以使用這兩種方式創(chuàng)建:一種是使用alloc方法旺嬉,另一種是使用array等一系列方法管行。那這兩種方法有什么區(qū)別:
使用alloc方法生成的對象自己持有(持有的概念通過下面的對比會清楚),當不再需要時自己釋放(調用release方法)邪媳,當一個對象的引用計數(shù)為0時不可以再讓變量調用release(非自己持有的對象不能釋放)捐顷。
使用array方法只是取得對象的存在,就是說你可以通過變量訪問這個對象悲酷,但是你不持有它套菜,當你不再需要使用這個對象時你不必調用release方法。你可以對變量調用retain方法來持有對象设易,當你不需要使用對象時調用release方法釋放對象逗柴。
為什么通過array方法獲得的對象有這個特性?
首先說明這不是ARC顿肺。這就要介紹autorelease了戏溺。
我們使用release方法會立即釋放一個對象,而使用autorelease方法會將對象注冊到autoreleasepool中屠尊,具體的步驟如下:
生成NSAutoreleasePool對象旷祸,對不需要被持有的對象調用autorelease方法,廢棄NSAutoreleasePool對象讼昆。當NSAutoreleasePool對象被廢棄時托享,調用過autorelease方法的對象都會被釋放。在iOS開發(fā)中,主線程的NSRunLoop負責對自動釋放池生成廢棄闰围,這里不再贅述赃绊,當然我們可以自己創(chuàng)建自動釋放池,及時廢棄大量占用內存的對象羡榴。需要注意一點:無論哪種類型的變量調用autorelease方法碧查、都是調用NSObject類的autorelease方法,但是NSAutoreleasePool類的autorelease方法已被該類重載校仑,如果NSAutoreleasePool的對象調用autorelease方法時會出現(xiàn)運行時錯誤忠售。
另外使用以下方法、或以以下方法開頭時意味著自己生成的對象自己持有:alloc迄沫、new稻扬、copy、mutablecopy邢滑。
ARC:
在MRC下腐螟,我們通過retain、release困后、autorelease來完成引用計數(shù)(內存管理),在ARC下如何記述如何管理呢衬廷?
所有權限修飾符:
__strong:id和對象類型默認的所有權限修飾符摇予。使用__strong修飾的變量在超出作用域時(或者手動置nil、被賦值等)吗跋,對象被廢棄侧戴。即隨著強引用的失效,引用的對象隨之釋放跌宛。
但是__strong還不夠“strong”酗宋,使用__strong時會出現(xiàn)相互強引用的情況:
相互強引用是內存泄漏的一種情況,對象得不到應有的釋放疆拘。這里詳細說一下相互強引用:
首先要理解這個過程:比如說有個類A蜕猫,它的一個實例a,類A中有一個類B的成員變量bb哎迄,a和a的成員變量bb都被初始化了回右,當a被廢棄時會怎么樣? ? a超出作用域時漱挚,a之前所引用的對象被釋放翔烁,然后變量bb被廢棄,bb之前所引用的對象被釋放旨涝。再來說這種情況蹬屹,有個類A,它的一個實例a,類A中有一個類B的成員變量bb慨默;有個類B秃踩,它的一個實例b,類B中有一個類A的成員變量aa业筏,a和b初始化之后憔杨,分別將a、b賦給aa蒜胖、bb消别。當a和b超出作用域之后,a所引用的對象沒有被釋放台谢,因為aa還在引用它寻狂,b所引用的對象沒有被釋放,因為bb還在引用它朋沮。
__weak提供弱引用蛇券,__weak不持有對象,也就是說對象失去強引用之后無論有多少弱引用都將被釋放樊拓。弱引用還會自動失效處于nil狀態(tài)纠亚。
__unsafe_unretained是不安全的所有權修飾符,使用該修飾符修飾的變量不屬于編譯器的內存管理對象筋夏,當其引用的對象被釋放后不會自動置nil蒂胞。C語言的結構體中,不能含有OC對象条篷,因為C語言沒有方法來管理結構體成員的生存周期骗随,要想加入OC對可以強制轉換為void *或使用__unsafe_unretained修飾符。
__autoreleasing修飾符:
這個修飾符是與MRC下的autorelease方法對應的修飾符赴叹。在ARC下不能使用autorelease方法鸿染,也不能使用NSAutoreleasePool類,但是可以使用@autoreleasepool { ?} 塊來替代NSAutoreleasePool的作用乞巧、使用__autoreleasing修飾符代替調用autorelease方法涨椒。
以下幾種情況非顯示的使用__autoreleaseing:
不是 ?以alloc、new摊欠、copy丢烘、mutableCopy開頭的方法 的返回值的對象 ?默認注冊到autoreleasePool中。
在訪問__weak修飾的變量時些椒,該變量默認被注冊到autoreleasePool中播瞳,因為__weak只持有對象的弱引用,在訪問的過程中很可能對象被廢棄了免糕。這樣可以保證在@autoreleasePool{}塊結束前對象都不會被釋放赢乓。
init方法返回的對象不注冊到autoreleasePool忧侧。(以init開頭的方法必須是實例方法,并且必須返回id類型或者該方法所在類(也可以是其父類或子類)類型的對象牌芋。(-(void)initialiaze方法除外)蚓炬。
要注意只有相同所有權修飾符相同的變量才可以賦值,否則編譯報錯躺屁,如果沒有報錯則說明編譯器自行幫你轉化了肯夏。
最后給出屬性與所有權限修飾符的關系:
assign__unsafe_unretained
copy__strong
retain__strong
strong__strong
unsafe_unretained ? __unsafe_unretained
weak__weak