黑馬程序員_OC語言的內存管理1

iOS,Android,Java培訓,期待與您的交流
對於面向對象的變成語言,程序需要不斷地創建對象。初始,創建的所有程序通常都有指針指向它,程序可能需要訪問這些對象的實例變量或調用這些對象的方法,隨着程序的不斷執行,程序再次創建了一些新的對象,而那些老的對象已經不會再被調用,也不再有指針指向他們,如果程序沒有回收他們佔用的內存,就會出現內存泄露。如果程序一直泄露內存,那麼可用內存就會越來越少,直到沒有足夠的內存,程序將會崩潰。
目前,主要有兩種管理內存的技術,一是引用計數,二是垃圾回收。iOS平臺目前只支持引用計數,Mac平臺支持垃圾回收。
引用計數通過給每個對象維護一個引用計數器,記錄該對象當前被引用的次數。當對象增加一次引用時,計數器加1;對象失去一次引用時,計數器減1;當引用計數爲0時,標誌着該對象的生命週期結束,系統自動回收該對象。
iOS的引用技術分爲手動引用計數和自動引用計數(ARC)。
1    手動引用計數
手動引用計數,就是右開發人員自己控制對象的引用計數,相關方法如下:
1、當使用alloc、new或者copy創建一個新對象時,新對象的引用計數器默認就是1。
2、給對象發送一條retain消息,可以使引用計數器值+1
3、給對象發送一條release消息,可以使引用計數器值-1
4、可以給對象發送retainCount消息獲得當前的引用計數器值
當一個對象的引用計數器值爲0時,那麼它將被銷燬,其佔用的內存被系統回收。一個對象被銷燬時,系統會自動向對象發送一條dealloc消息。所以一般會重寫dealloc方法,在這裏釋放相關資源,dealloc就像對象的遺言。一旦重寫了dealloc方法,就必須調用[super dealloc],並且放在最後面調用。要特別注意的時,不要直接調用dealloc方法,否則當系統調用dealloc方法,程序會崩潰。
//Person.h
@interface Person : NSObject

@property int age;

@end

//Person.m
@implementation Person
// 當一個Person對象被回收的時候,就會自動調用這個方法
- (void)dealloc
{
    NSLog(@"Person對象被回收");
    
    // super的dealloc一定要調用,而且放在最後面
    [super dealloc];
}
@end

//main.c
int main()
{
  
    Person *p = [[Person alloc] init];     // alloc之後,該對象的計數器爲1
    
    NSLog(@"計數器:%ld", [p retainCount]);      // 查看該對象的引用計數值

    [p release];  //釋放該對象,否則引起內存泄露
    

    return 0;
}

2    成員變量的引用計數
以上只是一個簡單類的內存管理,如果某個類的成員變量也引用其他類,事情就變得很複雜。爲了做好內存管理,有4個基本原則;
1.想使用(佔用)某個對象,就應該讓對象的計數器+1(讓對象做一次retain操作)
2.不想再使用(佔用)某個對象,就應該讓對象的計數器-1(讓對象做一次release)
3.誰retain,誰release
4.誰alloc,誰release
//Person.h,Car是已經定義好的類
@interface Person : NSObject
{
    Car *_car;
}

- (void)setCar:(Car *)car;
- (Car *)car;
@end

//Person.m
@implementation Person
- (void)setCar:(Car *)car
{
    if (car != _car)  //一定要判斷,否則_car指向的對象會發生內存泄露
    {
        // 對當前正在使用的車(舊車)做一次release
        [_car release];
        
        // 對新車做一次retain操作
        _car = [car retain];
    }
}

- (Car *)car
{
    return _car;
}

- (void)dealloc     //一定重寫該方法,否則_car指向的對象沒法釋放
{
    // 當人不在了,代表不用車了
    // 對車做一次release操作
    [_car release];
    
    NSLog(@"%d歲的Person對象被回收了", _age);
    
    [super dealloc];
}

@end


int main()
{
  
    Person *p = [[Person alloc] init];  //Person對象的引用計數爲1
    Car *c = [[Car alloc] init];  //Car對象的引用計數爲1  
    p.car = c;   //Car對象的引用計數變成2
    
    [c release];    //Car對象的引用計數變成1
    
    [p release];   //Car對象的引用計數變成0,Person對象的引用計數變成0  
    
    return 0;
}

3    帶有內存管理的合成存取方法
OC語言提供了了@property、@synthesize指令用於簡化setter和getter方法,同樣也提供了相應的指示符用於內存管理。
1.set方法內存管理相關的參數
* retain : release舊值,retain新值(適用於OC對象類型)
* assign : 直接賦值(默認,適用於非OC對象類型)
* copy : release舊值,copy新值 (一般用於NSString*)
2.是否要生成set方法
* readwrite : 同時生成setter和getter的聲明、實現(默認)
* readonly : 只會生成getter的聲明、實現
3.多線程管理
* nonatomic : 性能高 (一般就用這個)
* atomic : 性能低(默認)
4.setter和getter方法的名稱
* setter : 決定了set方法的名稱,一定要有個冒號 :
* getter : 決定了get方法的名稱(一般用在BOOL類型)
//Person.h,Car是已經定義好的類
@interface Person : NSObject
{
    Car *_car;
}
// retain : 生成的set方法裏面,release舊值,retain新值
@property (nonatomic,retain) Car *car;
@end

//Person.m
@implementation Person
- (void)setCar:(Car *)car
/*這段代碼,由系統自動生成
{
    if (car != _car)  //一定要判斷,否則_car指向的對象會發生內存泄露
    {
        // 對當前正在使用的車(舊車)做一次release
        [_car release];
        
        // 對新車做一次retain操作
        _car = [car retain];
    }
}

- (Car *)car
{
    return _car;
}
*/
- (void)dealloc     //一定重寫該方法,否則_car指向的對象沒法釋放
{
    // 當人不在了,代表不用車了
    // 對車做一次release操作
    [_car release];
    
    NSLog(@"%d歲的Person對象被回收了", _age);
    
    [super dealloc];
}

@end


int main()
{
  
    Person *p = [[Person alloc] init];  //Person對象的引用計數爲1
    Car *c = [[Car alloc] init];  //Car對象的引用計數爲1  
    p.car = c;   //Car對象的引用計數變成2
    
    [c release];    //Car對象的引用計數變成1
    
    [p release];   //Car對象的引用計數變成0,Person對象的引用計數變成0  
    
    return 0;
}

iOS,Android,Java培訓,期待與您的交流
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章