黑马程序员——内存管理的使用—例子篇

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------


1、简单的例子

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Person *person = [[Person alloc] init];//引用计数为1  
  2. NSLog(@"引用计数:%ld",[person retainCount]);  
  3.   
  4. //引用计数加1  
  5. [person retain];  
  6.   
  7. [person release];  
  8.   
  9. NSLog(@"引用计数:%ld",[person retainCount]);  
  10. [person release];  
我们创建了一个Person类,然后可以打印一下的引用计数值:1

当我们调用retain方法的时候,引用计数就会+1,当我们调用release方法的时候引用计数会-1

一旦系统发现引用计数为0的时候,就会销毁这个对象,调用dealloc方法


2、set方法来控制引用计数

这个例子简单吧,没什么问题的,现在我们把问题复杂化

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Dog *dog = [[Dog alloc] init];  
  2. [dog setName:@"小黑"];  
  3.   
  4. Dog *dog1 = [[Dog alloc] init];//引用计数为1  
  5. [dog setName:@"大黄"];  
  6.   
  7. Person *p1 = [[Person alloc] init];  
  8. [p1 setName:@"张三"];  
  9. [p1 setDog:dog];  
  10. [p1 setDog:dog1];//狗的引用替换成了大黄  
  11.   
  12. Person *p2 = [[Person alloc] init];  
  13. [p2 setName:@"李四"];  
  14. [p2 setDog:dog];  
  15.   
  16. //这里引用计数为1,这个和我们之前说的引用计数管理有矛盾,所以我们在使用的时候需要手动的retain  
  17. NSLog(@"引用计数为:%ld",[dog retainCount]);  
  18.   
  19. [dog1 release];//因为alloc的时候引用计数就为1了  
  20.   
  21. //这里就有一个问题了,dog1对象已经被销毁了,但是setDog对象还是用了dog1对象调用方法了,这就会报错了  
  22. //所以又对set方法进行改进了  
  23. [p1 setDog:dog1];  
  24.   
  25. //当人销毁的时候,还需要对狗的引用-1  
  26. //在人的dealloc方法中实现  
我们定义了两条狗,然后将这两条狗通过setDog方法设置到p1对象上,同时将第一条狗设置到p2对象上,这时候我们打印一下第一条狗的引用计数,发现他的引用计数是1,原因很简单,这个1是在alloc时候有的,但是现在是有问题的,因为第一条狗被p1和p2引用者,按照正常情况,第一条狗的引用计数为3的。所以这时候我们就需要修改一下Person类中setDog方法了

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. - (void)setDog:(Dog *)dog{  
  2.     //引用计数需要+1  
  3.     _dog = [dog retain];  
  4.       
  5.     //有时候可能需要替换Dog对象,所以这里还要注意释放Dog的引用  
  6. }  
我们需要手动的增加dog的引用计数,这样就正常了。


现在又有一个问题了,上面p1对象设置了第二条狗

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. [p1 setDog:dog1];//狗的引用替换成了大黄  
按照上面的setDog方法,我们又发现一个问题,现在p1引用的狗是第二条狗了,不是第一条,那么这时候按照正常情况第一条狗的引用计数-1,因为他已经不再被p1引用了。所以setDog方法还得修改:

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. - (void)setDog:(Dog *)dog{  
  2.     //使用nil去调用方法是没有错误的  
  3.     //但是当一个对象被销毁的时候,指针就变成野指针了,这时候调用方法会出错的  
  4.     [_dog release];  
  5.     _dog = [dog retain];  
  6. }  
这时候我们就在赋值之前,对_dog调用一次release方法,这样就解决了上面的那个问题。


但是现在还有一个问题:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. [dog1 release];//因为alloc的时候引用计数就为1了  
  2. NSLog(@"dog1:%ld",[dog1 retainCount]);  
  3. //这里就有一个问题了,dog1对象已经被销毁了,但是setDog对象还是用了dog1对象调用方法了,这就会报错了  
  4. //所以又对set方法进行改进了  
  5. [p1 setDog:dog1];  
在执行release代码之后,dog1的引用计数为1,这是继续调用setDog方法:

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. - (void)setDog:(Dog *)dog{  
  2.     //使用nil去调用方法是没有错误的  
  3.     //但是当一个对象被销毁的时候,指针就变成野指针了,这时候调用方法会出错的  
  4.     [_dog release];  
  5.     _dog = [dog retain];  
  6. }  
这时候_dog是dog1,继续调用release方法,执行完之后,引用继续为0了,对象被释放了,但是这时候dog参数的值还是dog1,那么在执行retain方法就会报错了,这个原因很简单,就是我们两次调用了setDog方法,将dog1设置了两次。中间调用一次release方法。所以解决这样的问题,我们在修改一下setDog方法:

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //第三种方式  
  2. - (void)setDog:(Dog *)dog{  
  3.     //这里的判断是因为setName方法可能会被多次调用  
  4.     if(_dog != dog){  
  5.         [_dog release];  
  6.         _dog = [dog retain];  
  7.     }  
  8. }  
我只需要判断一下,之前的属性值和当前需要设置的值是否相同。这种方式就是没有问题了,所以我们以后在写set方法的时候,这就是模板了。


3、销毁方法dealloc控制引用计数

现在假如p1被销毁了,那么对于dog1来说引用计数应该-1的,所以需要在Person类中的dealloc方法中修改一下:

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. - (void)dealloc{  
  2.     //对象类型的属性都需要在这里进行释放引用  
  3.     //对狗进行释放  
  4.     [_dog release];  
  5.     NSLog(@"dealloc is Executing");  
  6.     [super dealloc];  
  7. }  


4、初始化方法控制引用计数

现在还有一种情况,如果我们使用初始化方法来设置Dog属性值:

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. - (id)initWithDog:(Dog*)dog{  
  2.     //使用初始化的时候传入dog  
  3.     self = [super init];  
  4.     if(self != nil){  
  5.         //因为初始化方法只会调用一次,所以这里就没有做判断了  
  6.         [_dog release];  
  7.         _dog = [dog retain];  
  8.     }  
  9.     return self;  
  10. }  
我们这里的处理和setDog方法的处理方式一样,但是这里不需要做一次判断了,因为初始化方法只会调用一次。所以不会出现setDog的第三种情况。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值