iOS内存管理(一)

iOS内存管理 有两种方式:MRC(ManualReference Count人工引用计数)ARC(Auto Reference Count自动引用计数)

   整个ios内存管理的核心是  引用计数.

   C语言的内存管理:管理内存的开辟(malloc)和回收(free).

   OC内存管理与之不同:不直接管理内存的开辟和回收,管理引用计数.通过控制引用计数的加减,来实现内存的管理.引用计数01表示开辟了空间,10表示空间被系统回收了.

   我们所谓的内存管理,其实管理的是数值的加和减.间接控制开辟和回收.

    

   学习内存管理的目的:

   1.形成良好的内存管理习惯,减少甚至避免出现内存问题.

   2.一旦内存出现问题,能分析和解决内存问题(解决bug)

    

   影响 引用计数的  方法有以下几个

    1.  +(id)alloc;

   此方法继承自根类NSObject,用于创建对象,开辟的堆空间清零,同时将对象的引用计数 设置为1.是对象引用计数从01的过程

 

Person *p1=[[Person alloc]init];

 

 

   NSObject给我们提供一个查看俺对象引用计数的方法:

   -(NSUInteger)retainCount;

    NSLog(@"当前引用计数:%lu %p",[p1 retainCount],p1);

 

    Person *p2=[[Personalloc]init];

   NSLog(@"当前引用计数:%lu %p",[p2 retainCount],p2);

   只要alloc,对象肯定不是同一.最直观的表现,对象的首地址不一样.

 

 

2.- (id)retain;

   此方法继承自根类NSObject,作用是让receiver所对应的引用计数+1.并且返回receiver(对象首地址).

    Person*p3=[p1 retain];

    NSLog(@"

 

 

 

 

3. - (copy);

   此方法继承自根类NSObject,作用是拷贝一个receiver的副本,receiver所对应的对象引用计数保持不变,副本的引用计设置为1,返回副本的首地址.

   并不是 可以向所有对象 发送copy消息,只有接受了NSCopying协议的对象才可以接收copy消息.否则,会抛出异常,产生crash.

   [p2 copy];//注意此处会crash!

 

 

 

  4. - (void)release

    此方法继承自根类NSObject,作用是让receiver所对应的对象引用计数-1.无返回值.

    一般来说,谁产生了引用计数增加,谁要负责引用计数减少.

    比如 p1使用了alloc让引用计数增加了,p1不再使用的时候,应该使用向p1发送release消息,让引用计数减少.

    p2同理.

    p3通过retain让引用计数增加了,p3不再使用的时候,应该向p3发送release消息,让引用计数减少.

    [p1release];

    NSLog(@"p1 release 之后,p1的引用计数:%lu",[p1 retainCount]);

    NSLog(@"p1 release 之后,p3的引用计数:%lu",[p3retainCount]);

 

    [p3release];

   注意:当一个对象的引用计数 降到0的时候,对象所占有的堆内存会被系统给回收.回收之前会先执行receiver的一个方法 -(void)dealloc;

 

 

   当一个对象被销毁的时候,不能再使用这个对象了.最容易出现的问题就是 野指针异常.有时候回产生crash,有时候不会.关键要看,这块被回收的堆空间是否被别的对象使用了.如果暂时无对象使用,不会出现crash,如果已经有对象使用了这块内存,就会出现crash.

   野指针出现的crash是最难找的.

 

 p3=nil;

    p2=nil;

    p1=nil;//nil发送消息是不会出现crash,系统对nil做了处理,nil发送消息,什么也不执行.是一个空操作.

 

 

 很多开发者把 [xxrelease];  xx=nil;称作 安全释放.

 

 

 

 

5. - (id)autorelease;

    此方法继承自根类NSObject.作用是 延迟发送一条release消息(延迟调用release方法).

    究竟延迟到什么时候,取决于autoreleasepool.

    autoreleasepool自动释放池,主要作用是处理autorelease消息.iOS中有一个自动释放池类:NSAutoreleasePool

    

    

    Person*p10=[[Person alloc] init];

   Person *p11=[p10 retain];

   Person *p12=[p10 retain];

    

    NSAutoreleasePool*pool=[[NSAutoreleasePool alloc] init];

    

    

   NSLog(@"%lu %lu%lu",[p10 retainCount],[p11 retainCount],[p12retainCount]);

    [p10autorelease];

   NSLog(@"%lu %lu%lu",[p10 retainCount],[p11 retainCount],[p12retainCount]);

    

    

   [pool release];

    

    [p10autorelease];

   NSLog(@"%lu %lu%lu",[p10 retainCount],[p11 retainCount],[p12retainCount]);

 

 

运行结果:

2015-01-21 14:50:39.793 MRC[9207:1327141] 3 3 3

2015-01-21 14:50:39.794 MRC[9207:1327141] 3 3 3

2015-01-21 14:50:39.794 MRC[9207:1327141] 2 2 2

 

 

 

NSAutoreleasePool*pool=[[NSAutoreleasePool alloc] init];

    

    [pool release];

     可以看做是一个括号. 在括号里面 向对象发送  autorelease消息,才会被pool 管理.

    

     pool先记下都是谁 执行了 autorelease消息, (就像可变数组一样,把接受autorelease消息的receiver逐一addpool).

    

     pool不在需要的时候(:销毁时), pool中记录的receiver逐一发送release消息.

 

 

@autoreleasepool {//iOS5.0之后,采用这种格式,出大括号的瞬间,会让p13执行release消息,然后p10执行release消息,autoreleasepool以栈的方式工作.

       [p10 autorelease];

       [p13 autorelease];

    }

 

 

Copy

 

@interface Person : NSObject<NSCopying>

 

@property(nonatomic,copy) NSString *name;

@property(nonatomic,copy) NSString *sex;

@property(nonatomic,assign) NSInteger age;

 

- (instancetype)initWithName:(NSString *)name sex:(NSString *)sex age:(NSInteger)age;

 

@end

 

 

 

(1)这是浅拷贝 ,所谓的浅拷贝:对象是有两份的,但是 成员的内容 是公用一份

//重写方法

-(id)copyWithZone:(NSZone*)zone

{

    //self就是receiver,就是被拷贝的对象.

   Person *p=[[Person allocWithZone:zone]initWithName:self.name sex:self.sex age:self.age];

    return p;

}

 

 

(2)这是深拷贝,所谓的深拷贝:对象是两份,成员的内容也是两份.

- (id)copyWithZone:(NSZone *)zone

{

   Person *p=[[Person allocWithZone:zone]initWithName:[self.name copy] sex:[self.sex copy] age:self.age];

   return p;

}

 

 

 

(3)伪拷贝 并未拷贝

- (id)copyWithZone:(NSZone*)zone

{

   return [self retain];

}

 

 

 

- (instancetype)initWithName:(NSString *)name sex:(NSString *)sex age:(NSInteger)age

{

   self=[super init];

   if(self) {

       self.name=name;

       self.sex=sex;

       self.age=age;

    }

    return self;

}

 

 

 

注意:copy由调用者在外面释放

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值