OC中内存管理,引用计数的变化
从0~1:alloc , copy
+1 :retain
-1 :release 、autorelease
从1~0:dealloc
#+1/-1的内存管理
//引用计数:0 ——》1
Student *stu =[[Student alloc]init];
//retainCount属性,就是内存的引用计数
NSLog(@"stu.retainCount = %ld",stu.retainCount);
//retain 让引用计数+1
Student *stu1 = [stu retain]; //1 -> 2
NSLog(@"stu = %ld",stu.retainCount);
NSLog(@"stu1 = %ld",stu1.retainCount);
Student *stu2 =stu1; //2 -> 2
NSLog(@"stu1 = %ld",stu1.retainCount);
NSLog(@"stu2 = %ld",stu2.retainCount);
//引用计数是保存在内存中,不属于某个指针
[stu2 retain]; // 2 -> 3
NSLog(@"stu = %ld",stu2.retainCount);
//release 让引用计数-1
[stu2 release]; //3 ->1
stu2 =nil;
NSLog(@"stu = %ld",stu.retainCount);
[stu1 release]; //2 ->1
stu1 =nil;
NSLog(@"stu = %ld",stu.retainCount);
[stu release]; //1 ->1
stu = nil;
//内存实质上不会将引用计数从1-》0
//而是直接将内存释放
//再次访问空间会出现两种情况
//1.正常访问
//2.程序崩溃
NSLog(@"stu = %ld",stu.retainCount);
//过度释放
//程序一定会崩溃
[stu release];
//当将对象释放后,为防止过度释放和访问不存在的空间
//可以将对象设置成nil
stu = nil;
//给空对象发消息,不会引起程序奔溃
[stu release];
[stu release];
[stu name];
Student *student =[[Student alloc]init];
[student retain]; //1 -> 2
[student retain]; //2 -> 3
#autorelease
//autorelease 在自动释放池释放时释放
//自动释放池
@autoreleasepool {
//在自动释放池内部调用的autorelease
//会在自动释放池释放时,释放对应的对象
//自动释放池,在右大括号处释放自己
//在以后的某个时间,自动释放
[student autorelease];
student.name =@"liuxing";
NSLog(@"student = %ld",student.retainCount);
// [student autorelease];
// [student autorelease];
// [student autorelease];
// [student autorelease];
} //利用autorelease 释放时,过度释放,会崩溃在括号处
NSLog(@"student = %ld",student.retainCount);
//st 原本的空间产生泄漏
//st1 所指向空间,产生过度释放
Student *st = [[Student alloc]init];
Student *st1 = [[Student alloc]init];
st = st1;
// [st release];
// [st1 release];
// st = nil;
// st1 = nil;
NSString *str = [NSString stringWithFormat:@"lanou"];
[str retain];
[str retain];
NSLog(@"str = %ld",str.retainCount);
[str release];
[str release];
[str release];
//常量区
str = @"lanou";
[str release];
//当用无符号输出时,-1对应最大值
NSLog(@"str = %lu",str.retainCount);
[str release];
#内存管理法则:
//1.看到有alloc、retain、copy、就必须由release/autorelease
//2.谁使用alloc、retain、copy就由谁释放
//真正释放对象空间时,被系统自动调用
//释放本对象的所有空间
-(void)dealloc
{
NSLog(@"Student 对象被释放了!!!!");
[super dealloc];
}
#copy三种拷贝方式及用法详解
三种拷贝方式:
1.伪拷贝:只拷贝对象的地址
2.浅拷贝:创建新的对象空间,拷贝属性地址
3.深拷贝:创建新的对象空间,创建新的属性空间,拷贝属性内容
伪拷贝:原对象和新对象指的是同一个对象
浅拷贝:对象不同,但两者属性共用一块内存空间
深拷贝:对象不同,属性空间不同,两者之间无任何关系
以下的三种拷贝在.m文件中实现
伪拷贝
-(id)copyWithZone:(NSZone *)zone
{
return [self retain];
}
深拷贝
-(id)copyWithZone:(NSZone *)zone
{
//拷贝对象空间
Student *stu = [Student allocWithZone:zone];
//创建新的属性空间 属性重新指向
stu.name = [[NSString alloc]initWithString:self.name];
stu.sex =[[NSString alloc]initWithString:self.sex];
stu.hobby = [[NSMutableString alloc]initWithString:self.hobby];
stu.score = self.score;
stu.age = self.age;
return stu;
}
浅拷贝
-(id)copyWithZone:(NSZone *)zone
{
//产生一样的对象空间
Student *stu =[Student allocWithZone:zone];
//拷贝属性
stu.name = [self.name retain];
stu.sex =[self.sex retain];
stu.hobby =[self.hobby retain];
stu.score =self.score;
stu.age =self.age;
return stu;
}
#协议
(协议是一系列方法的集合,对于协议本身是不需要方法的实现;
一个类可以遵守多个协议,多个协议之间用逗号隔开;
协议只有声明没有实现,所以也没有.m文件;
协议可以被多个类去遵守)
如果要让一个类去遵守这个协议,那么就在这个类的.h文件中父类方法旁以< >尖括号的形式导入协议,并且要import导入协议文件
协议以@protocol开头,@end结束
协议中方法分为两类:
一、必须实现的方法,二、可选实现的方法
必须的
@required //默认
-(void)makemoney;
-(void)cooking;
可选的
@optional
-(void)handsome;
要想自定义类具有copy功能
就必须遵守NSCopying协议
copy方法,会调用对象的协议方法
-(id)copyWithZone:(NSZone *)zone
//student1 =[student2 copy];
//NSLog(@"hello world");
网友评论