iOS OC08,09_內存管理

//管理內存有三種方式,
    //1.是垃圾回收,java常見的管理內存的方法,系統來檢測對象是否被使用,是否被釋放
    //2.MRC手動管理引用計數,iOS管理內存的方式,程序員通過手動的方式來管理對象是否被釋放
    //3.ARC自動管理引用計數,基於MRC,系統自動的管理內存,以後我們還是先使用MRC,培養管理內存的習慣

//
//  Girl.h
//  OC08,09_內存管理
//
//  Created by dllo on 15/7/27.
//  Copyright (c) 2015年 zhozhicheng. All rights reserved.
//

#import <Foundation/Foundation.h>
//1.聲明協議
@protocol GirlDelegate <NSObject>

@required
-(void)married;

@optional
-(void)cook;
@end

@interface Girl : NSObject
//2.聲明代理人屬性
@property(nonatomic,assign)id<GirlDelegate>delegate;

-(void)getMarry;


@end







//
//  Girl.m
//  OC08,09_內存管理
//
//  Created by dllo on 15/7/27.
//  Copyright (c) 2015年 zhozhicheng. All rights reserved.
//

#import "Girl.h"

@implementation Girl
-(void)getMarry{
    [self.delegate cook];
}

@end
//
//  Boy.h
//  OC08,09_內存管理
//
//  Created by dllo on 15/7/27.
//  Copyright (c) 2015年 zhozhicheng. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Girl.h"
@interface Boy : NSObject<GirlDelegate,NSCopying>

-(void)dealloc;

+(Boy*)boy;

@property(nonatomic,retain)NSString *name;
@property(nonatomic,copy)NSString *hobby;
@property(nonatomic,retain)Girl *girls;

//自定義的初始化方法
-(instancetype)initWithName:(NSString *)name
                      hobby:(NSString *)hobby;
+(Boy *)boyWithName:(NSString *)name
              hobby:(NSString *)hobby;

@end




//
//  Boy.m
//  OC08,09_內存管理
//
//  Created by dllo on 15/7/27.
//  Copyright (c) 2015年 zhozhicheng. All rights reserved.
//

#import "Boy.h"

@implementation Boy


-(void)cook{
    NSLog(@"做飯吃");
}

-(void)dealloc{
    NSLog(@"對象被釋放了");

    //把成員變量所有+1操作全部減去
    [_name release];
    [_girls release];
    [_hobby release];

    [super dealloc];
}


+(Boy*)boy{
    Boy *b=[[Boy alloc] init];
    return [b autorelease];
}
//id是void *
//id是泛型指針,可以用在任何方法中,但是instancetype代表實例類型,用在自定義初始化方法,便利構造器作爲返回值類型使用,標識方法會返回一個對象回去
//-(instancetype)init{
//   Boy *b=[[Boy alloc] init];
//    return [b autorelease];
//}

- (id)copyWithZone:(NSZone *)zone{
    Boy *b=[Boy allocWithZone:zone];

    b.hobby=_hobby;
    b.name=_name;
    return b;

}



-(instancetype)initWithName:(NSString *)name
                      hobby:(NSString *)hobby{
    [super self];
    if (self) {
        self.name=name;   //從直接賦值變成方法賦值
        _hobby=hobby;
    }return self;
}


+(Boy *)boyWithName:(NSString *)name
              hobby:(NSString *)hobby{
    Boy *b=[[Boy alloc] initWithName:name hobby:hobby];
    //寫便利構造器最後別忘了autorelease
    return [b autorelease];
}


-(void)setName:(NSString *)name{
    if(_name!=name);
    [_name release];
    _name=[name retain];
}



@end




對象被創建出來之後他的引用計數retainCount就變成1

Boy *boy=[[Boy alloc] init];
NSLog(@"%ld",boy.retainCount);

結果

2015-07-27 17:47:40.331 OC08,09_內存管理[1562:152231] 1

//對對象的引用計數進行+1的操作

// //retain:對對象的引用計數進行+1

Boy *boy=[[Boy alloc] init];
NSLog(@"%ld",boy.retainCount);
[boy retain];
NSLog(@"%ld",boy.retainCount);
[boy retain];
[boy retain];
NSLog(@"%ld",boy.retainCount);

結果

2015-07-27 17:50:13.304 OC08,09_內存管理[1571:153537] 1
2015-07-27 17:50:13.305 OC08,09_內存管理[1571:153537] 2
2015-07-27 17:50:13.305 OC08,09_內存管理[1571:153537] 4

//release:對對象的引用計數進行-1的操作

[boy release];
NSLog(@"%ld",boy.retainCount);
[boy release];
[boy release];
[boy release];
NSLog(@"%ld",boy.retainCount);

結果

2015-07-27 17:54:44.714 OC08,09_內存管理[1580:155505] 1
2015-07-27 17:54:44.715 OC08,09_內存管理[1580:155505] 對象被釋放了
2015-07-27 17:54:44.715 OC08,09_內存管理[1580:155505] 1

註釋

//     //如果多次對對象進行釋放,會造成過度釋放,過度釋放也是最常見的內存問題(+1次數小於-1次數)
//    //[boy release];
//    //當對象的引用計數1->0時,會自動調用dealloc方法,dealloc纔是對應對象釋放的方法
//當對象調用release的時候,他的引用計數是1,這個對象就不再對他的引用計數進行-1操作,而是直接調用dealloc方法,所以我們在訪問對象引用計數還是1

幾個不同類型retain值

NSArray *arr=@[@"1",@"2",@"3",@"4"];
NSLog(@"%ld",arr.retainCount);

NSString *str=@"1111";
NSLog(@"%ld",str.retainCount);

NSMutableString *str2=[NSMutableString stringWithString:@"111111"];
NSLog(@"%ld",str2.retainCount);

NSDictionary *dic=@{@"1":@"2",@"3":@"4"};
NSLog(@"%ld",dic.retainCount);
NSLog(@"%p",str);
NSLog(@"%p",str2);

結果

2015-07-27 17:56:31.134 OC08,09_內存管理[1587:156279] 1
2015-07-27 17:56:31.134 OC08,09_內存管理[1587:156279] -1
2015-07-27 17:56:31.135 OC08,09_內存管理[1587:156279] 1
2015-07-27 17:56:31.135 OC08,09_內存管理[1587:156279] 1
2015-07-27 17:56:31.135 OC08,09_內存管理[1587:156279] 0x100002130
2015-07-27 17:56:31.135 OC08,09_內存管理[1587:156279] 0x100112ac0

註釋

NSString 的對象在全局靜態區,他的引用計數是-1,代表正整數的最大值,其他的對象都在堆區,

Boy *boy=[[Boy alloc] init];
[boy retain];
[boy retain];
NSLog(@"%ld",boy.retainCount);
//release馬上會把對象的引用計數-1,但是autorelease會延遲對對象的計數-1
[boy release];
NSLog(@"%ld",boy.retainCount);
[boy autorelease];
NSLog(@"%ld",boy.retainCount);
//自動釋放池
//只要對象用autorelease釋放會把對象放入到系統的自動釋放池中,等出了池子範圍,對象引用計數自動-1,這個相當於java的垃圾回收,對象釋放由系統來管理
 @autoreleasepool {
 [boy autorelease];
 NSLog(@"%ld",boy.retainCount);
 }NSLog(@"%ld",boy.retainCount);

結果

2015-07-27 19:00:44.667 OC08,09_內存管理[1602:162429] 3
2015-07-27 19:00:44.668 OC08,09_內存管理[1602:162429] 2
2015-07-27 19:00:44.668 OC08,09_內存管理[1602:162429] 2
2015-07-27 19:00:44.668 OC08,09_內存管理[1602:162429] 2
2015-07-27 19:00:44.668 OC08,09_內存管理[1602:162429] 1

// 內存管理原則:加多少減多少,加減做到平衡,減多了過度釋放,減少了沒有得到釋放

//對象的所有權:擁有所有權的對象可以對他進行release

Boy *b=[Boy boy];
[b retain];
NSLog(@"%ld",b.retainCount);
[b release];

結果

2015-07-27 19:05:11.838 OC08,09_內存管理[1610:164027] 2
 //便利構造器在返回對象的時候會加上一個autorelease,所以用便利構造器創建對象不需要對內存進行管理
NSArray *arr1=[[NSArray alloc] initWithObjects:@"1",@"2", nil];
NSArray *arr2=[NSArray arrayWithObjects:@"1",@"2",nil];
[arr1 release];
    NSArray *arr=@[@"1",@"2",@"3",@"4"];
    NSArray *newArr=[NSArray arrayWithArray:arr];
    NSLog(@"%@",newArr);
    NSLog(@"%ld",arr.retainCount);
    NSLog(@"%ld",newArr.retainCount);

結果

2015-07-27 19:07:04.008 OC08,09_內存管理[1624:164855] (
    1,
    2,
    3,
    4
)
2015-07-27 19:07:04.009 OC08,09_內存管理[1624:164855] 1
2015-07-27 19:07:04.010 OC08,09_內存管理[1624:164855] 1

//把一個不可變的變成可變的

NSArray *arr=@[@"1",@"2",@"3",@"4"];
NSMutableArray *arr1=[NSMutableArray arrayWithArray:arr];

NSMutableArray *arr2=[arr mutableCopy];
[arr2 addObject:@"5"];
NSLog(@"%@",arr2);


NSDictionary *dic=@{@"1":@"2",@"3":@"4"};
NSMutableDictionary *dic1=[dic mutableCopy];
NSLog(@"%@",dic1);

結果

2015-07-27 19:08:34.111 OC08,09_內存管理[1633:165509] (
    1,
    2,
    3,
    4,
    5
)
2015-07-27 19:08:34.112 OC08,09_內存管理[1633:165509] {
    1 = 2;
    3 = 4;
}

註釋

//系統的類要是實現copy功能,必須先簽訂拷貝NSCopying協議,然後實現對應的方法
//不可變的數組字典可以通過mutableCopy轉換成可變的數組字典
//mutableCopy出來的對象可變,copy是不可變的

舉例

Girl Boy文件

//
//  Girl.h
//  OC08,09_內存管理
//
//  Created by dllo on 15/7/27.
//  Copyright (c) 2015年 zhozhicheng. All rights reserved.
//

#import <Foundation/Foundation.h>
//1.聲明協議
@protocol GirlDelegate <NSObject>

@required
-(void)married;

@optional
-(void)cook;
@end

@interface Girl : NSObject
//2.聲明代理人屬性
@property(nonatomic,assign)id<GirlDelegate>delegate;

-(void)getMarry;


@end


//
//  Girl.m
//  OC08,09_內存管理
//
//  Created by dllo on 15/7/27.
//  Copyright (c) 2015年 zhozhicheng. All rights reserved.
//

#import "Girl.h"

@implementation Girl
-(void)getMarry{
    [self.delegate cook];
}

@end




//
//  Boy.h
//  OC08,09_內存管理
//
//  Created by dllo on 15/7/27.
//  Copyright (c) 2015年 zhozhicheng. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Girl.h"
@interface Boy : NSObject<GirlDelegate,NSCopying>

-(void)dealloc;

+(Boy*)boy;

@property(nonatomic,retain)NSString *name;
@property(nonatomic,copy)NSString *hobby;
@property(nonatomic,retain)Girl *girls;

//自定義的初始化方法
-(instancetype)initWithName:(NSString *)name
                      hobby:(NSString *)hobby;
+(Boy *)boyWithName:(NSString *)name
              hobby:(NSString *)hobby;

@end





//
//  Boy.m
//  OC08,09_內存管理
//
//  Created by dllo on 15/7/27.
//  Copyright (c) 2015年 zhozhicheng. All rights reserved.
//

#import "Boy.h"

@implementation Boy


-(void)cook{
    NSLog(@"做飯吃");
}

-(void)dealloc{
    NSLog(@"對象被釋放了");

    //把成員變量所有+1操作全部減去
    [_name release];
    [_girls release];
    [_hobby release];

    [super dealloc];
}


+(Boy*)boy{
    Boy *b=[[Boy alloc] init];
    return [b autorelease];
}
//id是void *
//id是泛型指針,可以用在任何方法中,但是instancetype代表實例類型,用在自定義初始化方法,便利構造器作爲返回值類型使用,標識方法會返回一個對象回去
//-(instancetype)init{
//   Boy *b=[[Boy alloc] init];
//    return [b autorelease];
//}

- (id)copyWithZone:(NSZone *)zone{
    Boy *b=[Boy allocWithZone:zone];

    b.hobby=_hobby;
    b.name=_name;
    return b;

}



-(instancetype)initWithName:(NSString *)name
                      hobby:(NSString *)hobby{
    [super self];
    if (self) {
        self.name=name;   //從直接賦值變成方法賦值
        _hobby=hobby;
    }return self;
}


+(Boy *)boyWithName:(NSString *)name
              hobby:(NSString *)hobby{
    Boy *b=[[Boy alloc] initWithName:name hobby:hobby];
    //寫便利構造器最後別忘了autorelease
    return [b autorelease];
}


-(void)setName:(NSString *)name{
    if(_name!=name);
    [_name release];
    _name=[name retain];
}


@end

運行

//Boy類使用Copy的方法
 Boy *boy=[Boy boyWithName:@"張陽陽" hobby:@"玩"];
 Boy *newBoy=[boy copy];
 NSLog(@"%@",newBoy.name);
 //如果自己的類想要實現copy功能,就必須先簽訂NSCopying協議,然後實現對應的協議方法,initWithZone,之後就可以使用copy的功能
 NSLog(@"%ld",boy.retainCount);
 NSLog(@"%ld",newBoy.retainCount);

結果

2015-07-27 19:13:02.102 OC08,09_內存管理[1644:168242] 張陽陽
2015-07-27 19:14:15.390 OC08,09_內存管理[1653:168927] 1
2015-07-27 19:14:15.390 OC08,09_內存管理[1653:168927] 1
    Boy *boy1=[[Boy alloc] init];
    [boy1 retain];
    [boy1 retain];
    NSLog(@"%ld",boy1.retainCount);
    NSMutableArray *arr=[NSMutableArray arrayWithObjects:boy1, nil];
    NSLog(@"%ld",[arr[0] retainCount]);

結果

2015-07-27 19:14:52.821 OC08,09_內存管理[1660:169279] 3
2015-07-27 19:14:52.822 OC08,09_內存管理[1660:169279] 4

註釋

// 當對象放入到容器Array或者字典中,對面會被容器進行一次持有,就是retain一次,他的引用計數會+1,主要是爲了防止空指針的問題
// //等對象從容器移除掉之後,相應的會-1

    Boy *b=[[Boy alloc] init];
    Girl *girl=[[Girl alloc]init];
    b.girls=girl;
    NSLog(@"%ld",girl.retainCount);

    Girl *girl2=[[Girl alloc] init];
    b.girls=girl2;
    NSLog(@"%ld",girl.retainCount);

結果

2015-07-27 19:16:00.235 OC08,09_內存管理[1667:169909] 2
2015-07-27 19:16:00.236 OC08,09_內存管理[1667:169909] 1

一個完整的類寫法

//
//  Person.h
//  OC08,09_內存管理
//
//  Created by dllo on 15/7/27.
//  Copyright (c) 2015年 zhozhicheng. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property(nonatomic,retain)NSMutableArray *arr;
@property(nonatomic,copy)NSString *name;
@property(nonatomic,assign)NSInteger age;


-(id)initWithName:(NSString *)name
              age:(NSInteger)age;

+(Person *)personWithName:(NSString *)name
                      age:(NSInteger)age;


@end
//
//  Person.m
//  OC08,09_內存管理
//
//  Created by dllo on 15/7/27.
//  Copyright (c) 2015年 zhozhicheng. All rights reserved.
//

#import "Person.h"

@implementation Person

-(id)initWithName:(NSString *)name
              age:(NSInteger)age{
    self=[super init];
    if (self) {
        self.name=name;
        self.age=age;
        //對象創建之後,裏面的數組也會創建好,不用在外面進行創建,避免因爲忘了,造成問題
        self.arr=[NSMutableArray array];
    }return self;
}

+(Person *)personWithName:(NSString *)name
                      age:(NSInteger)age{
    Person *per=[[Person alloc] initWithName:name age:age];
    return [per autorelease];

}
-(void)dealloc{
    [_arr release];
    [_name release];
    //age是棧區的,我們操作的是堆區
}


@end
    Person *per=[[Person alloc] initWithName:@"張陽陽" age:20];
    [per.arr addObject:@"1" ];
    NSLog(@"%@",per.arr);

結果

2015-07-27 19:18:09.427 OC08,09_內存管理[1675:171354] (
    1
)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章