天天看點

【黑馬程式員】---Objective-C記憶體管理總結

------- android教育訓練、 java教育訓練、期待與您交流! ----------

Objective-C記憶體管理

基本資料類型存儲在棧中,系統會自動釋放存儲空間,而OC對象存儲在堆中,系統不會自動回收對象,故而引起記憶體管理。

1.引用計數器的基本操作

每一個對象都有一個引用計數器,它在記憶體中占用4個位元組

(1)方法的基本使用

  1> retain :計數器+1,會傳回對象本身

 2> release :計數器-1,沒有傳回值

 3> retainCount :擷取目前的計數器

  4> dealloc

當一個對象要被回收的時候,就會調用

一定要調用[super dealloc],這句調用要放在最後面

(2).概念

 1> 僵屍對象 :所占用記憶體已經被回收的對象,僵屍對象不能再使用

 2> 野指針 :指向僵屍對象(不可用記憶體)的指針,給野指針發送消息會報錯(EXC_BAD_ACCESS)

 3> 空指針 :沒有指向任何東西的指針(存儲的東西是nil、NULL、0),給空指針發送消息不會報錯

Person p = [[Person alloc ] init];
[p retain];
[p release];
int size = [p retainCount];
[p release]
           
// 當一個Person對象被回收的時候,就會自動調用這個方法
- (void)dealloc
{
    NSLog(@"Person對象被回收");
    
    // super的dealloc一定要調用,而且放在最後面
    [super dealloc];
}
           

心得體會:

(1)當使用alloc、new或者copy建立一個新對象時,新對象的引用計數器預設就是1

(2)當一個對象的引用計數器值為0時,那麼它将被銷毀,其占用的記憶體被系統回收

(3)不要直接調用dealloc方法

(4)  一旦對象被回收了,它占用的記憶體就不再可用,堅持使用會導緻程式崩潰(野指針錯誤)

(5)OC不存在空指針錯誤,給空指針發送消息,不報錯

2.set方法的記憶體管理

 記憶體管理代碼規範:

  1.隻要調用了alloc,必須有release(autorelease)對象不是通過alloc産生的,就不需要release

 2.set方法的代碼規範

 1> 基本資料類型:直接複制

- (void)setAge:(int)age
 { 
    _age = age;
 }
           

2> OC對象類型

- (void)setCar:(Car *)car
 {
    // 1.先判斷是不是新傳進來對象
    if ( car != _car )
    {
        // 2.對舊對象做一次release
        [_car release];
 
        // 3.對新對象做一次retain
        _car = [car retain];
    }
 }
           

  3.dealloc方法的代碼規範

  1> 一定要[super dealloc],而且放到最後面

  2> 對self(目前)所擁有的其他對象做一次release

- (void)dealloc
 {
    [_car release];
    [super dealloc];
 }
           

心得體會:

如果你有個OC對象類型的成員變量,就必須管理這個成員變量的記憶體。

[email protected]

 1.set方法記憶體管理相關的參數

retain : release舊值,retain新值(适用于OC對象類型)

assign : 直接指派(預設,适用于非OC對象類型)

copy   : release舊值,copy新值

 2.是否要生成set方法

  readwrite : 同時生成setter和getter的聲明、實作(預設)

readonly  : 隻會生成getter的聲明、實作

 3.多線程管理

  nonatomic : 性能高 (一般就用這個)

atomic    : 性能低(預設)

 4.setter和getter方法的名稱

setter : 決定了set方法的名稱,一定要有個冒号 :

getter : 決定了get方法的名稱(一般用在BOOL類型)

@interface Person : NSObject

// 傳回BOOL類型的方法名一般以is開頭
@property (getter = isRich) BOOL rich;

@property (nonatomic, assign, readwrite) int weight;

@property (readwrite, assign) int height;

@property (nonatomic, assign) int age;

@property (retain) NSString *name;
@end
           

心得體會:

(1)不同類型的參數可以組合使用。

(2)一般都會添加nonatomic參數,提高性能。

4.循環引用

當一個類引用了另外一個類,另一個類又引用了這個類的時候,就叫做循環引用。

@class Person;

@interface Card : NSObject

@property (nonatomic, assign) Person *person;

@end
           
#import "Card.h"

@interface Person : NSObject

@property (nonatomic, retain) Card *card;

@end
           

心得體會:這種代碼編譯會報錯。當使用@class在兩個類互相聲明,就不會出現編譯報錯

@class  

僅僅是告訴編譯器,Card是一個類

@class和#include的差別:

(1)#import方式會包含被引用類的所有資訊,包括被引用類的變量和方法;@class方式隻是告訴編譯器在A.h檔案中 B *b 隻是類的聲明,具體這個類裡有什麼資訊,這裡不需要知道,等實作檔案中真正要用到時,才會真正去檢視B類中資訊

(2)@class相比#include而言,能提高效率。當#include引入的檔案更改時,所有引入的檔案都要重新編譯一遍

心得體會:

(1)在.m實作檔案中,如果需要引用到被引用類的實體變量或者方法時,還需要使用#import方式引入被引用類

(2)兩端循環引用的解決方案是,一端用retain一端用assign。

5.autorelease

(1) 給某個對象發送一條autorelease消息時,就會将這個對象加到一個自動釋放池中

(2)當自動釋放池銷毀時,會給池子裡面的所有對象發送一條release消息

(3)調用autorelease方法時并不會改變對象的計數器,并且會傳回對象本身

@autoreleasepool
 {
    // 1
    Person *p = [[[Person alloc] init] autorelease];
 
 }
           
1> alloc之後調用了autorelease,又調用release
 @autoreleasepool
 {
    // 1
    Person *p = [[[Person alloc] init] autorelease];
	// 0
	[p release];
 }
 
 // 2> 連續調用多次autorelease
 @autoreleasepool
 {
    Person *p = [[[[Person alloc] init] autorelease] autorelease];
 }
           

自動釋放池

(1) 在iOS程式運作過程中,會建立無數個池子。這些池子都是以棧結構存在(先進後出)

(2)當一個對象調用autorelease方法時,會将這個對象放到棧頂的釋放池

// 自動釋放池的建立方式
 // 1> iOS 5.0前
 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
 [pool release]; // [pool drain];
 
 
 // 2> iOS 5.0 開始
 @autoreleasepool
 {
    
 }
           

心得體會:

(1)autorelease實際上隻是把對release的調用延遲了,對于每一次autorelease,系統隻是把該對象放入了目前的autorelease pool中,當該pool被釋放時,該pool中的所有對象會被調用Release。

6.autorelease應用

(1)系統自帶的方法裡面沒有包含alloc、new、copy,說明傳回的對象都是autorelease的。

NSString *str2 = [NSString stringWithFormat:@"age is %d", 10];
           

(2)開發中經常會提供一些類方法,快速建立一個已經autorelease過的對象

+ (id)person
 {
    return [[[self alloc] init] autorelease];
 }
           

心得體會:

(1)建立對象時不要直接用類名,一般用self,這樣于子類調用。

繼續閱讀