OC 内存管理
//
// main.m
#import <Foundation/Foundation.h>
#import "person.h"
/*
堆内存的三种常见问题:
1.野指针问题:访问没有所有权的内存,如果想安全的访问,必须确保空间还在.
2.过度释放:对同一块空间释放多次,立即crash.
3.内存泄露:空间使用完之后没有及时的归还系统.
*/
/*
内存管理的三种方式:
1.垃圾回收机制(gc):由系统来管理内存,系统识别空间何时不使用,自动回收空间,不适合用于ios开发,java采用该机制
2.MRC机制:是手动引用计数机制,由开发人员开辟空间,并且显示添加引用计数修改的代码,能够灵活的控制空间何时释放.
3.ARC机制:自动引用计数机制是ios5.0推出的也是苹果推荐的内存管理方式,本质上还是基于MRC,只不过对于引用计数修改的代码由系统自动添加.
MRC和ARC都是基于引用计数机制的
*/
/*
内存管理黄金法则:
如果你对一个对象做了 alloc copy retain 操作之后你就拥有了对象的所有权,你就有责任对他进行release或者autorelease.
简单理解就是:就看自己有没有使用alloc copy,retain这三个方法,如果使用了就对应上release或者autorelease,没有使用,就和自己无关,不用管理.
*//*
能够让对象的引用计数发生改变的方法
1.alloc在堆区开辟空间,空间从无到有,引用计数从0到1;
2.retain 将原有对象的引用计数加1.
3.release 将原有对象的引用计数直接减1.
4autorelease延迟减1
5.copy.会在堆区开辟新的空间,对新的空间的计数加1,原有对象的引用计数不变.
*/
int main(int argc, const char * argv[]) {
// //alloc功能两个:开辟空间;让对象的引用计数由0变1.
// person *per=[[person alloc]init];
// NSLog(@"per=%p",per);
// NSLog(@"per.name=%p",per.name);
// //retainCount:它是系统提供的方法,用来计算一个对象的引用计数
// //retainCount:它是MRC情况下才会有的机制,所以我们使用的时候应该将ARC改为MRC
// NSLog(@"per=%lu",[per retainCount]);
// //retain是对象的引用计数+1;
//
// [per retain];//2
// NSLog(@"per=%lu",[per retainCount]);
// [per retain];//3
// [per retain];//4
// NSLog(@"per=%lu",[per retainCount]);
//
// //release:使用对象的引用计数-1
// [per release];
// [per release];
// [per release];
//
// NSLog(@"per=%lu",[per retainCount]);
//copy
//对对象发送一个copy消息,对象就会找到一个方法(copywithzone)方法执行
//copy原理:生成一个新对象,并且使新对象的引用计数为1,他不改变原始对象的引用计数
// person *per2=[per copy];
// // NSLog(@"per2=%lu",[per2 retainCount]);
//
// NSLog(@"per2=%p",per2);
// NSLog(@"per2.name=%p",per2.name);
//
//[per2 release];//自动调用dealloc方法
//@autoreleasepool : 自动释放池
//在ios5.0后推荐使用
// @autoreleasepool { }
//[[NSAutoreleasePool alloc]init];
//创建三个对象放入池子中
//我们在使用的时候一个对象只能使用一次autorelease ,不要多次调用
// @autorelease他和我们release不同,autorelease是在未来某一时刻释放,而这个未来某一时刻指的是碰到自动释放池之后才会释放,而release会立即释放
// person *p1=[[[person alloc]init]autorelease];
// NSLog(@"p1=%lu",[p1 retainCount]);
//
// //系统推荐:
// @autoreleasepool {
// person *p3=[[[person alloc]init]autorelease];
// @autoreleasepool {
// person *p4=[[[person alloc]init]autorelease];
// NSLog(@"p4=%lu",[p4 retainCount]);
// }
// NSLog(@"p3=%lu",[p3 retainCount]);
// }// }相当于自动释放池释放的标记
//自动释放池的对象被释放的时候,他里面等待的被释放的对象就会被释放
//自动释放池是一栈的形式存在的,在池子释放的时候,会对池子里的所有对象发送一条release消息,最后进入池子的会被最先释放
/*
copy和retain的区别
copy是创建一个县的对象,retain是创建一个指针,引用计数+1,copy表示两个对象的内容相同,新的对象retain为1,与旧有的对象引用计数无关,旧的对象没有发生变化,copy减少对上下文的依赖.
retain属性表示两个对象地址相同(就是建立了一个指针,进行了指针拷贝),内容肯定相同,这个对象的retain值+1,也就是说retain是指针拷贝,copy是内容拷贝.
*/
/*
在ios中并不是所有的对象都支持copy,mutablecopy,遵守NSCopying协议的类可以发送copy消息,遵守NSMutablecopy协议的类才可以发送mutablecopy消息,假如发送了一个没有遵守上述两个协议而发送copy或者mutablecopy那么就会发生议程,但是默认的ios类并没有遵守这两个协议,如果想自定义一个copy那么就必须遵守NSCopying,并且copywithzone方法,如果项自定义一个mutablecopy那么就必须遵守NSMutablecopying,并且实现mutableCopywithzone方法
*/
//copy:
//浅拷贝:
//不可变字符串,copy是浅拷贝.
// NSString *str=[[NSString alloc]initWithFormat:@"光光"];
// NSString *str1=[str copy];
//
// NSLog(@"str=%@,str1=%@",str,str1);
//
// NSLog(@"str= %lu,str1=%lu",[str retainCount],[str1 retainCount]);
// //深拷贝
// //深拷贝mutablecopy,拷贝出来的是一个可变的字符串对象
// NSMutableString *str3=[str mutableCopy];
// NSLog(@"str=%p,str3=%p",str,str3);
// NSLog(@"str=%lu,str3=%lu",[str retainCount],[str3 retainCount]);
//
//
/*
浅拷贝:拷贝的是指针,也就是不会申请一块新的内存空间,元对象的内存空间引用计数+1
深拷贝:拷贝的内容,也就是会申请一块新的内存空间,并把原内存空间的内容拷贝进去,所以原内存空间的引用计数依然还是1,新内存空间的引用计数由0变为1
*/
//copy深拷贝
// NSMutableString *Mstr=[[NSMutableString alloc]initWithFormat:@"小光"];
//
// NSString *mstr1 = [Mstr retain];
//
// NSLog(@"mstr1=%p,mstr=%p",Mstr,mstr1);
//
//
// NSString *mstr2=[Mstr copy];
// NSLog(@"mstr2=%p,Mstr=%p",mstr2,Mstr);
//
// // mutablecopy
//
// NSMutableString *mstr3=[Mstr mutableCopy];
// NSLog(@"mstr2=%p,Mstr3=%p",mstr2,mstr3);
//
/*
1.只有不可变字符串copy才是浅拷贝
2.不管源字符串是否可变,质押是用 mutableCopy 出来的字符串就是可变的(深拷贝).
*/
//数组内存管理:
person *p1=[[person alloc]init];
person *p2=[p1 copy];
NSLog(@"p1=%p,p2=%p",p1,p2);
NSLog(@"p1.name=%p,p2=name=%p",p1.name,p2.name);
NSLog(@"p1=%lu,p2=%lu",[p1 retainCount],[p2 retainCount]);
//把对象放入数组当中,对象的引用计数+1
NSArray *array=[NSArray arrayWithObjects:p1,p2, nil];
NSLog(@"p1=%lu,p2=%lu",[p1 retainCount],[p2 retainCount]);
//将对象再次放到数组当中,我们数组里边的元素(对象)引用计数继续+1.
NSMutableArray *marray=[[NSMutableArray alloc]initWithArray:array];
NSLog(@"p1=%lu,p2=%lu",[p1 retainCount],[p2 retainCount]);
//将对象从数组中移除,对象的引用计数-1
[marray removeObject:p1];
NSLog(@"p1=%lu,p2=%lu",[p1 retainCount],[p2 retainCount]);
//对数组进行一个release操作,数组内部元素的引用计数都会-1.
[marray release];
NSLog(@"p1=%lu,p2=%lu",[p1 retainCount],[p2 retainCount]);
[marray release];
return 0;
}