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

来源:互联网 发布:网络信息发布规范 编辑:程序博客网 时间:2024/06/06 21:38

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


内容:内存管理

为什么说他难呢?因为内存如果需要我们程序员去管理的话,那个难度肯定是很大的,如果是Java,垃圾回收器会把这份工作给做了,我们不需要关心,但是就是因为如此,Android运行速度上会慢一下,原因很简单,Java的垃圾回收器有很多收集算法的,这个在回收的过程中是很浪费时间的,效率自然就低了,但是如果这份工作给程序员自己去做的话,效率上肯定会增加,但是对于程序员来说任务就比较繁重了,而且还要特别的小心,千万不能造成内存溢出和泄露。

这里我们主要从四个方面来介绍一下内存管理

1、简单的例子来了解引用计数的使用

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

3、销毁方法来控制引用计数问题

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


下面就来简单看一下OC中的内存管理

这个例子有点复杂,我们慢慢分析

Dog.h

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //  
  2. //  Dog.h  
  3. //  24_MemeryManager  
  4. //  
  5. //  Created by jiangwei on 14-10-12.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import <Foundation/Foundation.h>  
  10.   
  11. @interface Dog : NSObject{  
  12.     NSString *_name;  
  13. }  
  14.   
  15. - (void) setName:(NSString *)name;  
  16.   
  17. @end  

Dog.m

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //  
  2. //  Dog.m  
  3. //  24_MemeryManager  
  4. //  
  5. //  Created by jiangwei on 14-10-12.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import "Dog.h"  
  10.   
  11. @implementation Dog  
  12.   
  13. - (void) setName:(NSString *)name{  
  14.     _name = name;  
  15. }  
  16.   
  17. @end  

Dog类中定义了name属性,并且给他提供了一个set方法


Person.h

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //  
  2. //  Person.h  
  3. //  24_MemeryManager  
  4. //  
  5. //  Created by jiangwei on 14-10-12.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import <Foundation/Foundation.h>  
  10.   
  11. @class Dog;  
  12. @interface Person : NSObject{  
  13.     Dog *_dog;  
  14.     NSString * _name;  
  15. }  
  16.   
  17. - (id)initWithDog:(Dog*)dog;  
  18. - (void)setName:(NSString *)name;  
  19. - (void)setDog:(Dog *)dog;  
  20. - (void)playDog;  
  21. - (Dog *)dog;  
  22.   
  23. - (void)dealloc;  
  24. @end  


Person.m

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //  
  2. //  Person.m  
  3. //  24_MemeryManager  
  4. //  
  5. //  Created by jiangwei on 14-10-12.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import "Person.h"  
  10.   
  11. @implementation Person  
  12.   
  13. - (id)initWithDog:(Dog*)dog{  
  14.     //使用初始化的时候传入dog  
  15.     self = [super init];  
  16.     if(self != nil){  
  17.         //因为初始化方法只会调用一次,所以这里就没有做判断了  
  18.         [_dog release];  
  19.         _dog = [dog retain];  
  20.     }  
  21.     return self;  
  22. }  
  23.   
  24. - (void)setName:(NSString *)name{  
  25.     //这里name也是对象,所以也是需要进行改写  
  26.     _name = name;  
  27.       
  28.     /* 
  29.      //这里的判断是因为setName方法可能会被多次调用 
  30.      if(_name != name){ 
  31.         [_name release]; 
  32.         [name copy];//这里使用了copy,而没有使用retain,这个是字符串独有的,其他对象类型都是使用retain的 
  33.      } 
  34.      */  
  35. }  
  36.   
  37. //第一种方式  
  38. /* 
  39. - (void)setDog:(Dog *)dog{ 
  40.     //引用计数需要+1 
  41.     _dog = [dog retain]; 
  42.      
  43.     //有时候可能需要替换Dog对象,所以这里还要注意释放Dog的引用 
  44. } 
  45.  */  
  46.   
  47. //第二种方式  
  48. /* 
  49. - (void)setDog:(Dog *)dog{ 
  50.     //使用nil去调用方法是没有错误的 
  51.     //但是当一个对象被销毁的时候,指针就变成野指针了,这时候调用方法会出错的 
  52.     [_dog release]; 
  53.     _dog = [dog retain]; 
  54. } 
  55.  */  
  56.   
  57. //第三种方式  
  58. - (void)setDog:(Dog *)dog{  
  59.     //这里的判断是因为setName方法可能会被多次调用  
  60.     if(_dog != dog){  
  61.         [_dog release];  
  62.         _dog = [dog retain];  
  63.     }  
  64. }  
  65.   
  66. - (void)playDog{  
  67.     NSLog(@"playDog");  
  68. }  
  69.   
  70. - (Dog *)dog{  
  71.     return _dog;  
  72. }  
  73.   
  74. - (void)dealloc{  
  75.     //对象类型的属性都需要在这里进行释放引用  
  76.     //对狗进行释放  
  77.     [_dog release];  
  78.     NSLog(@"dealloc is Executing");  
  79.     [super dealloc];  
  80. }  
  81.   
  82. @end  
Person类中有一个Dog的属性,然后提供了set方法。代码有点复杂,我们后面会详细说明

下面来看一下测试代码

main.m

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //  
  2. //  main.m  
  3. //  24_MemeryManager  
  4. //  
  5. //  Created by jiangwei on 14-10-12.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import <Foundation/Foundation.h>  
  10.   
  11. #import "Person.h"  
  12. #import "Dog.h"  
  13.   
  14. //内存管理  
  15. //alloc用来创建对象,创建完成之后,引用计数为1,只调用一次  
  16. //retain使引用计数+1,可以多调用几次  
  17. //release使引用计数-1,可以多调用几次  
  18. //当引用计数为0的时候会调用dealloc  
  19. //最新的Xcode版本默认情况下会开启ARC机制的,当开启这个机制之后,我们就不能手动的显示调用这些方法,编译器会报错  
  20. //所以我们可以将这个默认状态的ARC关闭,但是这个只是为了测试使用  
  21.   
  22. int main(int argc, const charchar * argv[]) {  
  23.   
  24.     /* 
  25.     Person *person = [[Person alloc] init];//引用计数为1 
  26.     NSLog(@"引用计数:%ld",[person retainCount]); 
  27.      
  28.     //引用计数加1 
  29.     [person retain]; 
  30.      
  31.     [person release]; 
  32.      
  33.     NSLog(@"引用计数:%ld",[person retainCount]); 
  34.     [person release]; 
  35.      */  
  36.       
  37.       
  38.     Dog *dog = [[Dog alloc] init];  
  39.     [dog setName:@"小黑"];  
  40.       
  41.     Dog *dog1 = [[Dog alloc] init];//引用计数为1  
  42.     [dog setName:@"大黄"];  
  43.       
  44.     Person *p1 = [[Person alloc] init];  
  45.     [p1 setName:@"张三"];  
  46.     [p1 setDog:dog];  
  47.     [p1 setDog:dog1];//狗的引用替换成了大黄  
  48.       
  49.     Person *p2 = [[Person alloc] init];  
  50.     [p2 setName:@"李四"];  
  51.     [p2 setDog:dog];  
  52.       
  53.     //这里引用计数为1,这个和我们之前说的引用计数管理有矛盾,所以我们在使用的时候需要手动的retain  
  54.     NSLog(@"引用计数为:%ld",[dog retainCount]);  
  55.       
  56.     [dog1 release];//因为alloc的时候引用计数就为1了  
  57.       
  58.     //这里就有一个问题了,dog1对象已经被销毁了,但是setDog对象还是用了dog1对象调用方法了,这就会报错了  
  59.     //所以又对set方法进行改进了  
  60.     [p1 setDog:dog1];  
  61.       
  62.     //当人销毁的时候,还需要对狗的引用-1  
  63.     //在人的dealloc方法中实现  
  64.       
  65.     Person *p3 = [[Person alloc] initWithDog:dog1];  
  66.     [dog1 release];//dog1的引用计数:0  
  67.       
  68.     [p3 playDog];  
  69.       
  70.     [p3 release];  
  71.       
  72.     return 0;  
  73. }  


下面我们来详细说明一下:

首先如果想演示这个例子的话,需要修改一下设置:



最新的XCode默认是会自动选上ARC(Automatic Reference Counting),如果我们不把这个手动关闭的话,代码中会报错的。

alloc用来创建对象,创建完成之后,引用计数为1,只调用一次

retain使引用计数+1,可以多调用几次

release使引用计数-1,可以多调用几次

当引用计数为0的时候会调用dealloc

黄金法则:每次调用alloc一次,都需要调用release一次,他们两是成对出现的

0 0