日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

iOS内存管理编程指南

發布時間:2025/7/14 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 iOS内存管理编程指南 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

iOS下內存管理的基本思想就是引用計數,通過對象的引用計數來對內存對象的生命周期進行控制。具體到編程時間方面,主要有兩種方式:

1:MRR(manual retain-release),人工引用計數,對象的生成、銷毀、引用計數的變化都是由開發人員來完成。

2:ARC(Automatic Reference Counting),自動引用計數,只負責對象的生成,其他過程開發人員不再需要關心其銷毀,使用方式類似于垃圾回收,但其實質還是引用計數。

iOS不支持垃圾回收機制,這點與Mac OS有所不同。

ARC是Xcode 4.2之后加入的新特性,可能很多開發人員并不習慣使用,但使用ARC給開發帶來的便利是顯而易見的,鼓勵大家都去嘗試一下。

ARC的具體介紹及使用細則大家可以參考蘋果官方文檔,本文主要介紹MRR。


一:基本原則

關于MRR,我總結了一句話:是你的,就是你的;不是你的,就不是你的。

雖然看上去比較廢話,但揭示了MRR內存管理里的一個核心原則,“只負責你擁有的對象的生命周期”,也就是說,如果你對一個對象有所有權,那么你就要負責其回收的工作,否則,你不需要,也不能取回收你不擁有的對象。

那些對象屬于“擁有”范疇呢?

1:所有使用alloc, new, copy或mutabelCopy,以及這些關鍵詞開頭的函數返回的對象,你都是擁有所有權的,也就是要負責這些對象的內存回收工作。這是iOS開發中的一種約定,所以,當你編寫自己的alloc, new或copy類型的函數時,也請遵循這樣的命名規范。

2:retain返回的對象,擁有所有權。例如顯示調用retain函數返回的結果,或者synthesize 的retain類型的成員變量。

3:所有使用其他函數返回的對象,沒有所有權。

4:返回的對象的引用,沒有所有權。

5:autorelease返回的對象沒有所有權。

舉例說明:

?

[cpp]?view plaincopy
  • //1:使用alloc函數生成,有所有權??
  • NSString*?stringA?=?[[NSString?alloc]?init];??
  • stringA?=?@"abc";??
  • [stringA?release];??
  • ??
  • //2:使用initWithString返回對象,無所有權??
  • NSString*?stringB?=?[NSString?stringWithString:?@"abc"];??
  • ??
  • //3:顯示調用retain返回對象,?擁有所有權??
  • NSString*?stringC?=?[[NSString?stringWithString:?@"abc"]?retain];??
  • stringC?=?@"def";??
  • [stringC?release];??
  • ??
  • //4:retain類型成員變量,擁有所有權??
  • @property?(retain)?NSString*?stringD;??
  • ??
  • @synthesize?stringD?=?_stringD;??
  • ??
  • -?(void)?dealloc??
  • {??
  • ????[_stringD?release];??
  • ??????
  • ????[super?dealloc];??
  • }??
  • ??
  • //5:通過引用返回的對象無所有權??
  • NSString**?stringERef?=?[self?stringRef];??
  • *stringERef?=?@"abc";??

  • 二:成員變量的內存管理

    ?

    注意上面的例子4,將成員變量聲明為retain并synthesize時,編譯器會幫你生成對應變量的setter與getter,其中, 生成的setter形式如下:

    ?

    [cpp]?view plaincopy
  • -?(void)?setStringD:?(NSString*)?newString??
  • {??
  • ????[newString?retain];??
  • ????[_stringD?release];??
  • ????_stringD?=?newString;??
  • }??

  • 首先獲得newString的所有權,然后釋放掉已經擁有的_stringD(其實此對象有可能并沒有被釋放,取決與其release后的引用計數是否為0), 再將newString的值賦給_stringD,這樣,獲得了新的,釋放了舊的,就完成了對象所有權的釋放與獲得。注意retain與release的調用順序,避免了同一個對象賦值引起的懸空指針問題。

    ?

    當成員變量聲明為assign和copy時,其生成的setter形式如下:

    ?

    [cpp]?view plaincopy
  • //copy??
  • -?(void)?setStringD:?(NSString*)?newString??
  • {??
  • ????NSString*?temp?=?[newString?copy];??
  • ????[_stringD?release];??
  • ????_stringD?=?temp;??
  • ??????
  • }??
  • ??
  • //assign??
  • -?(void)?setStringD:?(NSString*)?newString??
  • {??
  • ????_stringD?=?newString;?????
  • }??

  • copy類型的成員變量也是擁有所有權的,也要在dealloc函數中顯式釋放。而assign不是。

    ?

    很多人對self.stringD = @"abc"的調用形式比較困惑; 其實,編譯器會將此語句自動轉換為[self.setStringD:@"abc"];

    還有一點要注意,聲明成員類型時只有copy,沒有mutableCopy,那么,如果一個成員變量是MutableArray,且被聲明成copy類型,但編譯器生成的setter中調用的是copy,而不是MutableCopy,所以,向MutableArray類型的成員插入數據時就會報錯,因為其保存的真正類型不是MutableArray,而是Array. 這種情況有兩個解決方案:一是將改變量類型聲明為retain形式; 二是手動編寫setter,調用mutableCopy函數。


    NSObject函數聲明了dealloc函數來清理內存,所有有“retain, copy”類型成員變量的類都要實現這個函數。在其內,要調用相應對象的release函數,不要忘記在【最后】調用[super dealloc];


    說到成員變量的聲明周期,還要提一下IBOutlet類型的變量,默認情況下, IBOutlet對象的類型都是retain的,由于這些對象來自界面文件(xib, storyboard),所以其出事化過程無需關心,其他處理方式與普通成員變量大體相同,只有一點,需要在- ?(void) viewDidUnload函數中將這些變量置空, 如下所示:

    ?

    [cpp]?view plaincopy
  • -?(void)?viewDidUnload??
  • {??
  • ????self.outletA?=?nil;??
  • ????self.outletB?=?nil;??
  • ????[super?viewDidUnload];??
  • }??

  • 當出現內存警告時,viewDidUnload將會被調用。前面提到過,self.outletA = nil 等價于[self setOutletA: nil], 所以,在出現內存警告的情況下,IBOutlet類型的對象會被釋放。

    ?


    三:容器對象與內存管理

    iOS中,容器對象對其內的對象擁有所有權,也就是說,當一個對象被插入到容器內時,其retainCount會加一,從容器內移除時,其retainCount會減一,當容器本身被release時,期內所有對象的retainCount都會減一。如下代碼所示:

    ?

    [cpp]?view plaincopy
  • NSString*?stringA?=?[[NSString?alloc]?init];//stringA的retainCount:?1??
  • NSArray*?array?=?[[NSArray?alloc]?init];??
  • [array?addObject:?stringA];//stringA的retainCount:2??
  • [stringA?release];//stringA的retainCount:1??
  • [array?release];//retainCount:?0??

  • ?

    四:稀缺資源的管理

    稀缺資源包括文件,網絡連接,緩存等,這些資源是很關鍵的系統資源,系統內其他應用可能會隨時需要這些資源,所以,這些資源就不適合作為類的成員變量了,因為dealloc的實際調用時間,是否真正調用是我們無法控制的,很有可能造成稀缺資源被無意義的占用,二其他應用卻無法獲得相應資源。所以,隨時申請隨時釋放是最好的選擇。


    五:AutoRelease

    簡單說,autorelease對象的釋放動作由AutoReleasePool完成,所有autorelease對象在其【對應】的AutoReleasePool釋放的過程中,都會受到一條release消息,也就是說,pool析構的實際也就是autorelease對象析構的時機,注意,這里的【對應】指的是離改autorelese最近的那一個AutoRelasePool。

    有這么幾種情況必須自己創建AutoReleasePool:

    1:程序沒有界面,也就是沒有消息循環的程序,

    2:一個循環內創建大量臨時的autorelease對象,那么寫法最好是這樣的:

    ?

    [cpp]?view plaincopy
  • NSAutoReleasePool*?outPool?=?[[NSAutoReleasePool?alloc]?init];??
  • for?(int?index?=?0;?index?!=?1000000;?++index)?{??
  • ????NSAutoReleasePool*?pool?=?[[NSAutoReleasePool?alloc]?init];??
  • ????NSString*?temp?=?[[[NSString?alloc]?init]?autorelease];??
  • ????[pool?drain];??
  • }??
  • [outPool?release];??

  • 若果沒有循環中的pool, 那么直到結束循環之前,這1000000個autorelease 臨時對象都不會被釋放掉,占用大量內存。

    ?

    3:線程函數內需要有AutoReleasePool對象,否則期內生成的autorelease對象在線程函數結束時不會被釋放(此條對Cocoa-Touch不適用)。

    4:普通函數返回對象,這里的普通函數指的是非alloc, new, copy, mutablecopy開頭的函數,為了確保返回的對象有效,需要將返回的對象設為autorelease,如下所示:

    ?

    [cpp]?view plaincopy
  • -?(NSString*)?returnString??
  • {??
  • ????NSString*?tempString?=?[[NSString?alloc]?init];??
  • ????tempString?=?@"autorelease";??
  • ????return?[tempString?autorelease];??
  • }??

  • 實際上,iOS SDK中絕大多數普通函數返回的都是autorelease對象。

    ?


    六:其他注意事項

    1:避免循環引用,如果兩個對象互相為對方的成員變量,那么這兩個對象一定不能同時為retain,否則,兩個對象的dealloc函數形成死鎖,兩個對象都無法釋放。

    2:不要濫用autorelease,如果一個對象的生命周期很清晰,那最好在結束使用后馬上調用release,過多的等待autorelease對象會給內存造成不必要的負擔。

    3:編碼過程中,建議將內存相關的函數,如init, dealloc, viewdidload, viewdidunload等函數放在最前,這樣比較顯眼,忘記處理的概率也會降低。

    4:AutoReleasePool對象在釋放的過程中,在IOS下,release和drain沒有區別。但為了一致性,還是推薦使用drain。



    轉載于:https://www.cnblogs.com/songfeixiang/p/3733753.html

    總結

    以上是生活随笔為你收集整理的iOS内存管理编程指南的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。