iOS开发学习第二十二课——内存管理

来源:互联网 发布:java 0x 转换 int 编辑:程序博客网 时间:2024/06/02 06:50
OC中堆区常见的三种错误:
         1.
过度释放:对一个对象释放了不止一次
         2.
野指针:访问没有所有权的内存,如果想要访问就必须要保证内存还在(也就是指针指向了一个无效的内存)
         3.
内存溢出:开辟的内存没有得到及时的释放,也就是在使用完内存之后没有及时释放内存
       
         OC
当中内存管理方式:ARC / MRC
         ARC:
自动引用计数(自动管理内存) 由开发人员开辟空间,但是由系统自动释放内存,本质还是基于MRC,这是系统默认的内存管理方式,也是苹果推荐使用的方式
        
         MRC:
手动引用计数(手动管理内存) 由开发人员开辟空间,在使用完对象之后由开发人员手动及时释放内存;;;;比起ARC的好处就是能够灵活地控制空间何时释放
        
        

        
 内存管理机制:采用引用计数机制
        
 影响引用计数的几个方法:
         1.alloc 
 在堆区开辟内存,空间从无到有,引用计数由01
         2.retain 
 将原有的对象的引用计数+1
         3.copy 
 拷贝出一个新的对象,将新的对象引用计数+1,原有的对象的引用计数不变
         4.release 
 将原有的对象的引用计数-1
         5.autorelease  
 在将来的某一个时刻会将引用计数-1
      
       
#import
#import "Person.h"
int
 main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *per = [[Person alloc] init];//此时per01
       
 //retaincount 记录当前对象的引用计数
       
 NSLog(@"per = %lu",[per retainCount]);
       
       
 Person *per1 = [per retain];//per 12
       
 NSLog(@"per = %lu",[per retainCount]);//per --- 2
       
 NSLog(@"per = %lu",per.retainCount);//per --- 2
       
 NSLog(@"per1 = %lu",per1.retainCount);//per1 ---- 2
       
        [per1
 release];
       
 NSLog(@"per = %lu",per.retainCount);//per --- 1
       
 NSLog(@"per1 = %lu",per1.retainCount);//per1 ---- 1
       
        [per1
 retain];
       
 NSLog(@"per = %lu",per.retainCount);//per --- 2
       
 NSLog(@"per1 = %lu",per1.retainCount);//per1 ---- 2
       
       
 Person *per2 = [per1 retain];
       
 NSLog(@"per = %lu",per.retainCount);//per --- 3
       
 NSLog(@"per1 = %lu",per1.retainCount);//per1 ---- 3
       
 NSLog(@"per2 = %lu",per2.retainCount);//3
       
        [per
 release];
        [per
 release];
        [per
 release];//per ---- 0  对象的引用计数为零时,系统会自动调用dealloc方法,回收空间
       
 //当代码执行到这里的时候,此时对象的空间已经被系统收回,如果以后再次使用per指针,则会出现野指针问题,所以,我们需要将指针per置为nil
        per =
 nil;
        per1 =
 nil;
        per2 =
 nil;
       
 NSLog(@"per = %lu",per.retainCount);
       
 //为什么对象在销毁时本来该对象的引用计数为0,输出时反而为1 ?
       
       
 
       
       
       
 //内存管理的几道练习题
       
 Person *stu1 = [[Person alloc] init];// 0 --- 1
       
 Person *stu2 = [[Person alloc] init];// 0 --- 1
        stu2 = stu1;
       
 NSLog(@"stu1 = %lu",stu1.retainCount);
       
 NSLog(@"stu2 = %lu",stu2.retainCount);
        [stu1
 release];
       
       
 //第二种情况
       
 //NSString当中,当使用 alloc initWithFormat:创建字符串对象的时候,如果是要在控制台Unicode编码输出的话,那就是对象指向堆区,如果是ASCII码表中,系统会根据字符串所占的空间的大小来分配空间,有可能不分配堆区内存,此时也就是对象可能指向常量区也可能指向堆区
       
 NSString *str = [[NSString alloc] initWithFormat:@"MingGe"];
       
 NSLog(@"str = %lu",str.retainCount);//如果对象指向的不是堆区空间的话,则输出一个无穷大的数值
       
 //%lu --- 无穷大的数值
       
 //%ld --- 输出-1
        str =
 @"lanou";
       
 NSLog(@"str = %ld",str.retainCount);
       
       
 //什么时候才能满足引用计数概念?
       
 //1.必须是对象调用
       
 //2.对象必须指向堆区
       
 //注意:如果指向了其他区的话则输出无穷大的数值
       
    }
   
   
 //手动添加一个自动释放池
   
 @autoreleasepool {
       
 //对象如果发送了autorelease消息,autorelease过的对象会找离它最近的释放池,然后出了释放池,则自动释放池销毁时会找到autorelease过的对象,同时向对象发送一次release消息
       
 Person *per2 = [[Person alloc] init];
        [per2
 autorelease];//调用这个会立马销毁
    }
   
   
   
 //copy的使用
   
 //创建一个Person对象
   
 Person *perOld = [[Person alloc] init];
   
 //为属性赋值
    perOld.
name = @"XiaoLong";
    perOld.
sex = @"m";
    perOld.
age = 19;
    perOld.
score = 89;
   
 //当对一个类的对象进行copy操作时,需要将该类服从遵守NSCopying协议,同时实现协议里的一个方法
   
 //创建一个Person对象,接收拷贝出来的新的对象
   
 Person *perNew = [perOld copy];
   
 //copy拷贝  在堆区开辟一个新的空间,perNew的引用计数+1,perOld不变
   
 //释放
    [perOld
 release];
    [perNew
 release];
   
 NSLog(@"perNew name = %@  sex = %@  age = %lu  score = %.2f",perNew.name,perNew.sex,perNew.age,perNew.score);
   
 //置空
    perNew =
 nil;
    perOld = nil;

    return 0;
}


Person.h
***************************
#import
@interface Person : NSObject<</span>NSCopying>//遵守NSCopying协议

@property (nonatomic ,retain)NSString *name;
@property (nonatomic ,retain)NSString *sex;
@property (nonatomic ,assign)NSInteger age;
@property (nonatomic ,assign)CGFloat score;
- (void)dealloc;
@end

***************************
Person.m
#import "Person.h"
@implementation Person
//实现NSCopying里的方法
- (
id)copyWithZone:(NSZone *)zone{
   
 //开辟一份新的空间,与原对象所开辟的空间一样
   
 //zone:原有对象的空间的大小
   
 //第一步:创建一个新的对象
   
 Person *per = [Person allocWithZone:zone];
   
 //第二步:将原有对象的内容拷贝到新的空间上(也就是为新的对象赋值)
    per.
name = self.name;
    per.
age = self.age;
    per.
sex = self.sex;
    per.
score = self.score;
   
 //将新对象返回即可
   
 return per;
}

//销毁方法,当前该类的对象的引用计数为零时则会自动调用,用来回收对象的空间
- (
void)dealloc{
   
 NSLog(@"oh my god!,我被销毁了!");
   
 //调用父类该方法,销毁对象内存,此时才是真正回收内存
    [
super dealloc];
}
@end
0 0