[學習筆記—Objective-C]《Objective-C-基礎教程 第2版》第九章 記憶體管理

來源:互聯網
上載者:User

標籤:objective-c   ios   ios開發   記憶體管理   

記憶體管理:

  • 確保在需要的時候分配記憶體,在程式運行結束時釋放佔用的記憶體
  • 如果只分配記憶體而不釋放記憶體,則會發生記憶體流失(leak memory),程式的記憶體佔用量不斷增加,最終會被耗盡並導致程式崩潰。
  • 不要使用任何剛釋放的記憶體,否則可能誤用陳舊的資料,如果記憶體已經載入了其他資料,將會破壞這些新資料。
9.1 對象生命週期

對象的生命週期:

  1. 誕生:通過alloc或new方法實現
  2. 生存:接受訊息並執行操作
  3. 交友:通過複合以及向方法傳遞函數
  4. 死去:被釋放掉
9.11 引用計數

關於引用計數的操作:

  • 增加對象的保留計數器的值:發送retain 。方法:-(id) retain //傳回值為id類型
[[Car retain] setTire: tire atIndex:2];//car對象保留計數器的值+1並執行setTire的操作
  • 減少對象的保留計數器的值:發送release。方法:(oneway void)release;
  • 獲得保留計數器當前的值:retainCount。方法:-(NSUInteger) retainCount;//格式化方法:%ld
  • 對象的保留計數器歸0時,系統會自動向對象發送dealloc訊息。
  • 可以在自己的對象中重寫dealloc方法,這樣可以釋放掉已經分配的全部相關資源,不能直接調用dealloc方法。
9.12 對象所有權
  • 某個實體擁有一個對象時,該實體就要負責將其擁有的對象進行清理
    • 如果一個對象內有指向其他對象的執行個體變數,則稱該對象擁有這些對象
    • 如果一個函數建立了一個對象,則稱該函數擁有這個對象
main(){Car *car = [Car new];Engine *engine = [Engine new];//engine擁有engine對象[car setEngine: engine];//car擁有engine對象}

注意:main()和Car類都擁有engine對象,如何釋放?

  • 讓Car類在setEngie方法中保留engine對象,main()負責釋放engine對象,Car類完成任務時再釋放engine對象
9.13 存取方法中的保留和釋放
-(void)setEngine: (Engine *)newEngine{    [newEngine retain];    //先保留新的對象    [engine release];      //釋放舊的對象    engine = newEngine;
9.14 自動釋放
-(NSString *) description{    NSString *description = [[NSString alloc] initWithFormat:@"I am %d years old", 4];    return (destription);}main{    NSString *desc = [someObject description];    NSLog(@"@",desc);    [desc release];}

注意:在description方法中建立的字串對象如何釋放?

9.15 所有對象放入池中
-(id)autorelease;//返回接受這條訊息的對象
  • 當給一個對象發送autorelease訊息時,是將對象添加到了自動釋放池中,當自動釋放池被銷毀時,會像該池中的所有對象發送release訊息。
-(NSString *) description{    NSString *description = [[NSString alloc] initWithFormat:@"I am %d years old", 4];    return ([destription autorelease]);//對象暫時放入池中,等調用NSLog代碼結束後,自動釋放池會被自動銷毀}main(){    NSLog(@"@",[someObject description]);}
9.16 自動釋放池銷毀時間 略9.17 自動釋放池的工作流程
int main (){    NSAutoreleasePool *pool;    pool = [[NSAutoreleasePool alloc] init];    RetainTracker *tracker;    tracker = [RetainTracker new]; // count: 1    [tracker retain]; // count: 2    [tracker autorelease]; // count: still 2,自動釋放池有一個引用指向了該對象,當自動釋放池被銷毀時,將給tracker對象發送一條release訊息。保留計數器的值仍然大於0,仍處於活動狀態。    [tracker release]; // count: 1    NSLog (@"releasing pool");    [pool release]; //dealloc方法調用    return (0);}
9.2 Cocoa的記憶體管理規則
  • 使用new,alloc,或copy方法建立對象時,該對象的保留計數器為1。
  • 如果通過其他對象獲得一個對象時,假設該對象的保留計數器值為1,而且一景被設定為自動釋放,那麼不需要執行任何操作確保該對象得到清理。
  • 如果打算一段時間擁有對象,則需要保留它並確保在操作完成時釋放它。
  • 如果保留了某個對象,就需要最終釋放或自動釋放該對象。必須保持retain方法和release方法的使用次數相等。

注意:當擁有一個對象的時候,需要弄清楚:怎樣獲得對象的?打算擁有多長時間?

9.21 臨時對象

並未打算長期擁有對象的情況下:臨時對象

  • 如果是用new,alloc,copy方法獲得的這個對象,就需要安排好該對象的記憶體釋放
  • new,alloc,copy以外的方法獲得對象,則可以假設該對象被返回時保留計數器的值是1而且被設定為自動釋放。
9.22 擁有對象

在多段代碼中一直擁有某個對象,將她們加入到諸如NSArray或NSDictionary集合中

  • 如果使用了new,alloc,copy方法獲得了一個對象,只需要在擁有該對象的dealloc方法中釋放它即可。
-(void)dostuff{    flonkArray = [NSMutableArray new]; //count:1}
-(void) dealloc{    [flonkArray release]; //count:0    [super dealloc];}
  • 如果使用new,alloc,copy以外的方法獲得了一個對象,需要保留該對象,因為在事件迴圈結束後或自動釋放池被銷毀時,該對象會收到一條release訊息。
-(void)dostuff{    flonkArray = [NSMutableArray arrayWithCapacity:17]; //count:1,autoreleased}
-(void) dealloc{    [flonkArray release]; //count:0     [super dealloc];}

注意:自動釋放池被清理的時間是完全確定的:在代碼中你自己手動銷毀;使用AppKit時在事件迴圈結束時結束。

9.23 記憶體回收:自動記憶體管理機制

記憶體回收行程定期檢查變數和對象並且跟蹤它們的指標,發現沒有任何變數指向某個對象時,就將該對象視為應該丟棄的垃圾。

如果執行個體變數指向某個對象,一定要將該執行個體賦值為nil,取消對該對象的引用並告知記憶體回收行程該對象可以清理了。

注意:

  • 記憶體回收只支援OSX開發,無法用在ios應用程式上。蘋果公司不建議在自己的代碼中使用autorelease方法,也不要使用會返回自動釋放對象的一些便利的方法:stringWith:
  • 記憶體回收行程在運行時工作,通過返回的代碼定期檢查對象
9.24 自動引用計數
  • 自動引用計數(automatic refrence counting,ARC):系統追蹤對象並決定哪一個仍會使用,哪一個不會再用到。

  • ARC在編譯時間進行工作的,在代碼中插入了retain和release語句。

  • 有效範圍:可保留的對象指標

    • 代碼塊指標
    • Objective-C指標
    • 通過attribute((NSObject))類型定義的指標
  • 使用ARC滿足的條件:

    • 能夠確定哪些對象需要記憶體管理
    • 能夠表面如何管理對象
    • 有可行的辦法傳遞對象的所有權
  • A引用了B,B的引用計數器+1,強指標;被引用的+1

  • A釋放了B,B的引用計數器-1;被釋放的-1

  • 歸零弱引用:zeroing weak reference 若引用的對象被釋放的情況下,若引用會被設定為0

聲明歸零弱引用:

  • _weak NSString *mystring
  • @property (weak) NSString *myString

注意:記憶體管理的關鍵字和特性是不能一起用的

記憶體回收機制禁用的前提下才能使用ARC
轉換之前確保代碼符合ARC的需求
一旦轉換成ARC版本,就不可以再恢複了

  • 擁有者許可權:為了讓ARC便於工作,需要告訴編譯器哪個對象時指標的擁有者。

    • (_bridge)傳遞指標但不會傳遞它的所有權
    cfstring = (_bridge CFStringRef)theString;//指標的所有權仍然由theString保留
    • (_bridge_retain):所有權轉移到non-ROP上

      cfstring = (_bridge_retain CFStringRef)theString; //cfstring擁有指標並且保留計數器+1
    • (_bridge_transfer):所有權交給ROP

      ARC擁有對象並能確保它會像其他ARC對象一樣得到釋放
9.3 異常

NSException類來表示異常

  • 拋出異常(提出異常):處理異常的行為,通知異常的行為
  • 捕捉異常:處理被拋出的異常的行為

如果一個異常被拋出但是沒有被捕捉到,程式會在異常斷點處停止運動並通知有這個異常。

9.31 與異常有關的關鍵字
  • @try:定義用來測試的代碼塊決定是否拋出異常
  • @catch:定義用來處理已拋出異常的代碼塊
  • @finally:無論是否有拋出異常都會執行代碼塊
  • @throw:拋出異常
9.32 捕捉不同類型的異常
  • 多個@catch代碼塊,處理代碼應該按照從具體到抽象的順序排序
9.33 拋出異常
  • 當程式檢測到了異常,就必須向處理它的代碼塊報告這個異常
    • 使用@“throw異常名”
    • 向某個NSException對象發送raise訊息
NSException *theException = [NSException exceptionWithName: ];@throw theException; //拋出異常,可以用在其他對象上[theException rasie];//拋出異常,raise只對NSException對象有效

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

[學習筆記—Objective-C]《Objective-C-基礎教程 第2版》第九章 記憶體管理

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.