內(nèi)存管理
為什么要了解內(nèi)存管理手形?
了解內(nèi)存管理之后啥供,其實(shí)發(fā)現(xiàn)很多東西與我們編寫代碼關(guān)系不大,但是為什么還要了解它呢库糠?
在IOS剛在國內(nèi)興起的時(shí)候伙狐,很多時(shí)候是手動(dòng)內(nèi)存管理(也就是接下來說的MRC)的,那個(gè)時(shí)候往往一份代碼最近艱難的地方就是控制內(nèi)存管理瞬欧,所以這是必學(xué)的贷屎,但是現(xiàn)在有了自動(dòng)內(nèi)存管理(RAC)那就簡單了很多了。不過你也為這就不用了解內(nèi)存管理了艘虎?我覺得不是唉侄,在不了解內(nèi)存管理之前,我在對屬性野建,代碼為什么這個(gè)更好属划,為什么這么寫上很多地方幾乎是處于一種不識廬山真面目的狀態(tài)。但是在了解內(nèi)存管理之后候生,許多疑惑的地方也就豁然開朗了所以同眯,舉個(gè)例子:不理解常見的循環(huán)引用問題,這些問題會(huì)導(dǎo)致內(nèi)存泄漏唯鸭,最終使得應(yīng)用運(yùn)行緩慢或者被系統(tǒng)終止進(jìn)程嗽测。(理解它不能保證你代碼寫的漂亮,但不理解它就會(huì)讓你代碼崩潰)
所以作為一個(gè)好的IOS開發(fā)者,內(nèi)存管理應(yīng)該是基礎(chǔ)唠粥。
一、Objective-C內(nèi)存管理的對象
IOS開發(fā)中停做,內(nèi)存中的對象主要有兩類晤愧,一類是值類型,比如int蛉腌、float官份、struct等基本數(shù)據(jù)類型,另一類是引用類型烙丛,也就是繼承自NSObject類的所有的OC對象舅巷。前一種值類型不需要我們管理,后一種引用類型是需要我們管理內(nèi)存的河咽。
為什么值類型不需要管理钠右,而引用類型需要管理呢?那是因?yàn)樗麄兎峙鋬?nèi)存方式不一樣忘蟹。
值類型會(huì)被放入棧中飒房,他們依次緊密排列,在內(nèi)存中占有一塊連續(xù)的內(nèi)存空間媚值,遵循先進(jìn)后出的原則狠毯。引用類型會(huì)被放到堆中,當(dāng)給對象分配內(nèi)存空間時(shí)褥芒,會(huì)隨機(jī)的從內(nèi)存當(dāng)中開辟空間嚼松,對象與對象之間可能會(huì)留有不確定大小的空白空間,因此會(huì)產(chǎn)生很多內(nèi)存碎片锰扶,需要我們管理献酗。
棧內(nèi)存與堆內(nèi)存從性能上比較,棧內(nèi)存要優(yōu)于堆內(nèi)存少辣,這是因?yàn)闂W裱冗M(jìn)后出的原則凌摄,因此當(dāng)數(shù)據(jù)量過大時(shí),存入棧會(huì)明顯的降低性能漓帅。因此锨亏,我們會(huì)把大量的數(shù)據(jù)存入堆中,然后棧中存放堆的地址忙干,當(dāng)需要調(diào)用數(shù)據(jù)時(shí)器予,就可以快速的通過棧內(nèi)的地址找到堆中的數(shù)據(jù)。
值類型和引用類型之間是可以相互轉(zhuǎn)化的捐迫,把值類型轉(zhuǎn)化為引用類型的過程叫做裝箱乾翔,比如把int包裝為NSNumber,這個(gè)過程會(huì)增加程序的運(yùn)行時(shí)間,降低性能反浓。而把引用類型轉(zhuǎn)為值類型的過程叫做拆箱萌丈,比如把NSNumer轉(zhuǎn)為float,在拆箱的過程中雷则,我們一定要注意數(shù)據(jù)原有的類型辆雾,如果類型錯(cuò)誤,可能導(dǎo)致拆箱失敗月劈,因此會(huì)存在安全性的問題度迂。手動(dòng)的拆箱和裝箱,都會(huì)增加程序的運(yùn)行時(shí)間猜揪,降低代碼可讀性惭墓,影響性能。
在IOS開發(fā)過程中而姐,棧內(nèi)存中的值類型系統(tǒng)會(huì)自動(dòng)管理腊凶,堆內(nèi)存中的引用類型是需要我們管理的。每個(gè)OC對象內(nèi)部都專門有四個(gè)字節(jié)來存儲(chǔ)引用計(jì)數(shù)器毅人,它是一個(gè)整數(shù)吭狡,表示對象被引用的次數(shù),通過它可以判斷對象是否被回收丈莺,如果引用計(jì)數(shù)為0划煮,對象回收,不為0不回收缔俄。當(dāng)對象執(zhí)行alloc弛秋、new或者retain時(shí),引用計(jì)數(shù)加1俐载,release時(shí)蟹略,引用計(jì)數(shù)減1。
二遏佣、Objective-C管理內(nèi)存的方式
Objective-c中提供了兩種內(nèi)存管理機(jī)制MRC(Mannul Reference Counting)和ARC(Automatic Reference Counting)挖炬,分別提供對內(nèi)存的手動(dòng)和自動(dòng)管理,來滿足不同的需求状婶。
1.MRC(人工引用計(jì)數(shù))意敛,手動(dòng)管理內(nèi)存。
所有的對象都需要手動(dòng)的添加retain膛虫、release代碼來管理內(nèi)存草姻。使用MRC,需要遵守誰創(chuàng)建稍刀,誰回收的原則撩独。
當(dāng)引用計(jì)數(shù)為0的時(shí)候,必須回收,引用計(jì)數(shù)不為0综膀,不能回收澳迫,如果引用計(jì)數(shù)為0,但是沒有回收僧须,會(huì)造成內(nèi)存泄露纲刀。如果引用計(jì)數(shù)為0,繼續(xù)釋放担平,會(huì)造成野指針。為了避免出現(xiàn)野指針锭部,我們在釋放的時(shí)候暂论,會(huì)先讓指針=nil。
2.ARC(自動(dòng)引用計(jì)數(shù))拌禾,自動(dòng)管理內(nèi)存取胎。
ARC是IOS5推出的新功能,通過ARC湃窍,可以自動(dòng)的管理內(nèi)存闻蛀。在ARC模式下,只要沒有強(qiáng)指針(強(qiáng)引用)指向?qū)ο竽校瑢ο缶蜁?huì)被釋放觉痛。
屬性
在OC中定義變量,可以自己來定義變量的setter方法來設(shè)置變量值茵休,用getter方法來獲取變量值,但是當(dāng)變量數(shù)量增多時(shí)薪棒,還采用手動(dòng)添加setter/getter方法來操作變量,就會(huì)使得程序代碼量大大增加,于是就出現(xiàn)了 @property 來快速聲明設(shè)置獲取變量的值的方法榕莺。
@property是一個(gè)屬性訪問聲明以及聲明getter,setter方法俐芯,
擴(kuò)號內(nèi)支持以下幾個(gè)屬性:(getter=getterName,setter=setterName钉鸯,設(shè)置setter與getter的方法名,retain吧史,copy,assign.......)
在聲明property屬性后唠雕,有2種實(shí)現(xiàn)選擇
@synthesize?? 作用是實(shí)現(xiàn)屬性的,如getter贸营,setter方法.?
編譯器期間,讓編譯器自動(dòng)生成getter/setter方法及塘。
當(dāng)有自定義的存或取方法時(shí)莽使,自定義會(huì)屏蔽自動(dòng)生成該方法
@dynamic
告訴編譯器,不自動(dòng)生成getter/setter方法笙僚,避免編譯期間產(chǎn)生警告
然后由自己實(shí)現(xiàn)存取方法
如果@synthesize和@dynamic都沒寫芳肌,那么默認(rèn)的就是@syntheszie var = _var;
在開發(fā)過程中經(jīng)常要用到定義屬性,@property和@synthesize是經(jīng)常用到的關(guān)鍵字,那么到底該如何正確定義一個(gè)屬性呢亿笤,我們需要了解其中用到的關(guān)鍵字翎迁。
nonatomic?禁止多線程,變量保護(hù)净薛,提高性能汪榔。(一般只要不用多線程都會(huì)選擇用nonaomic)
atomic?是OC使用的一種線程保護(hù)技術(shù),基本上來講肃拜,是防止在寫未完成的時(shí)候被另外一個(gè)線程讀取痴腌,造成數(shù)據(jù)錯(cuò)誤。而這種機(jī)制是耗費(fèi)系統(tǒng)資源的
assign?此標(biāo)記說明設(shè)置器直接進(jìn)行賦值 燃领,賦值特性士聪,不涉及引用計(jì)數(shù),弱引用對基礎(chǔ)數(shù)據(jù)類型 (NSInteger猛蔽,CGFloat)和C數(shù)據(jù)類型(int, float,double, char)等等
copy?對NSString 它指出剥悟,在賦值時(shí)使用傳入值的一份拷貝÷猓拷貝工作由copy方法執(zhí)行区岗,此屬性只對那些實(shí)行NSCopying協(xié)議的對象類型有效,表示兩個(gè)對象內(nèi)容相同毁枯,新的對象retain為1 慈缔,與舊有對象的引用計(jì)數(shù)無關(guān)。
retain對其他NSObject和其子類對參數(shù)進(jìn)行release舊值后众,再retain新值胀糜,新對象的引用計(jì)數(shù)+1;
指定retain會(huì)在賦值時(shí)喚醒傳入值的retain消息蒂誉。此屬性只能用于Objective-C對象類型教藻,而不能用于Core
Foundation對象。(原因很明顯右锨,retain會(huì)增加對象的引用計(jì)數(shù)括堤,而基本數(shù)據(jù)類型或者Core Foundation對象都沒有引用計(jì)數(shù)——譯者注)。
注意: 把對象添加到數(shù)組中時(shí)绍移,引用計(jì)數(shù)將增加對象的引用次數(shù)+1悄窃。
copy?對NSString 它指出,在賦值時(shí)使用傳入值的一份拷貝蹂窖≡梗拷貝工作由copy方法執(zhí)行,此屬性只對那些實(shí)行NSCopying協(xié)議的對象類型有效瞬测,表示兩個(gè)對象內(nèi)容相同横媚,新的對象retain為1 纠炮,與舊有對象的引用計(jì)數(shù)無關(guān)。
retain是指針拷貝灯蝴,copy是內(nèi)容拷貝恢口。
weak?weak比assign多了一個(gè)功能,當(dāng)對象消失后自動(dòng)把指針變成nil穷躁,好處不言而喻耕肩。弱引用除了不決定對象的存亡外,其他與強(qiáng)引用相同问潭。即使一個(gè)對象被持有無數(shù)個(gè)若引用猿诸,只要沒有強(qiáng)引用指向他,那麼其還是會(huì)被清除狡忙。
strong用來修飾強(qiáng)引用的屬性,一塊內(nèi)存(一個(gè)對象)當(dāng)沒有 strong 類型的指針指向它時(shí)两芳,它就會(huì)被釋放;ARC中使用去枷,與MRC中retain同義,使用之后是复,計(jì)數(shù)器+1删顶。
weak用來修飾弱引用的屬性,當(dāng)一塊內(nèi)存(一個(gè)對象)被釋放時(shí)淑廊,指向它的 weak 類型指針就
所以逗余,如果一般情況下屡律,我們都不希望字串的值跟著str變化座硕,所以我們一般用 copy 來設(shè)置string的屬性屿愚。如果希望字串的值跟著賦值的字串的值變化泵肄,可以使用 strong鼠哥,retain偏塞。