------- android培训、java培训、IOS培训、期待与您交流! ----------
OC内存管理
1. 内存管理基本概念+总结
// 内存管理管理范围:任何继承了NSObject的对象,对其他基本数据类型无效
// 栈空间的东西程序运行完毕会自动回收,对象是在堆空间的,必须手动回收
// 内存管理-02-引用计数器
// 每个OC对象都有自己的引用计数器,表示对象被引用的次数
// 每个对象都会专门分配4个字节的空间来存放自己的引用计数器,新对象刚刚诞生的时候计数器值为1
// 当使用alloc,new,copy创建一个新对象的时候,新对象的引用计数器默认为1
// 计数器为0,对象空间就会被回收,如果不为零,除非整个程序被完全退出,否则占用的内存会一直占用
// 4.引用计数器的操作
// 1>给对象发送一条retain消息,可以使引用计数器+1(retain方法返回对象本身)
// 2>给对象发送一条release消息,可以使引用计数器-1
// 3>可以给对象发送retainCount消息获得当前的引用计数器值
// 5.对象的销毁
// 当一个对象被销毁时,系统会自动向对象发送一条dealloc消息
// 一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言
// 一旦重写了dealloc方法,就必须调用[superdealloc],并且放在最后面调用
// 注意,非常重要,不要直接调用dealloc方法
//一旦对象被回收了,它占用的内存就不可再用,坚持使用会导致程序崩溃(即野指针错误)
一,计数器的基本操作
1>retian : +1
2>release: -1;
3>retainCount : 获得计数器值
二,set方法的内存管理
1>set方法的实现
- (void)setCar:(Car *)car
{
if(_car !=car)
{
[_car release];
_car = [car retain];
}
}
2> dealloc方法的实现(不要直接调用dealloc,由系统自动调用)
- (void)dealloc
{
[_car release];
[super dealloc];
}
三,@property参数
1> OC对象类型
@property (nonatomic, retian) 类名 *属性名;
@property (nonatomic,retain) Car *car;
@property (nonatomic,retain)id car;
//被retain过的属性,必须在dealloc方法中release属性
- (dealloc)
{
[car release];
[super dealloc]
}
2> 非OC对象类型 (int\float\enum\struct)
@property (nonatomic,assign) 类型名称 属性名;
@property (nonatomic,assign)int age;
四,autorelease
1.系统自带的方法中,如果不包含alloc,new,copy,那么这些对象方法都是autorelease过的
[NSStringstringWithFormat:...];
[NSDate date];
2.开发中经常写一些类方法快速创建一个autorelease的对象
*创建对象的时候不要直接用类名,用self
2. remain与release-多文件与set
// 有alloc,必须调用一次release,有retain,必须调用一次release
// 自己创建的小孩,自己得负责
// 内存管理-04-野指针和空指针
// 计数器为0为被回收,成为僵尸对象,这时仍然指向僵尸对象(不可用内存对象)的指针叫做野指针
// EXC_BAD_ACCESS报错,访问了一块坏的内存(已经被回收,不可再使用的内存),又叫做野指针错误
// 所指内存为僵尸对象的时候,为了防止成为野指针成为野指针错误,这时应该把指针清空 p= nil;
// OC中不存在空指针错误,给空指针发送消息,不报错
// 人死不能复生,变成僵尸对象后不能通过发retain复生
// 1.release,release方法的基本使用
// 2.野指针,僵尸对象
// 计算机管理总结
// 1.方法的基本使用
// 1>retain ;计数器+1;会返回对象本身
// 2>release :计数器-1,没有返回值
// 3>retaincount:获取当前的计数器
// 4>dealloc
// * 当一个对象要被回收的时候,就会调用
// * 一定要调用[superdealloc],这句调用要放在最后面
// 2.概念
// 1>僵尸对象:所占内存已经被回收的对象,僵尸对象不能再被使用
// 2>野指针:指向僵尸对象(不可用内存)的指针,给野指针法消息会报错
//3>空指针:没有指向任何东西的指针(储存的东西是nil,NULL,0),给空指针发送消息不会报错
// 加一个指向对象,调用一次retain使计数器+1;少一个对象,调用一次release使计数器-1;计数器为零的时候,房间,book撤销;
// 1.Person, Book举例
// 2.QQ堂游戏开房间举例,玩家对象,房间对象
// >多房间跳转,撤销当前房间的指向,调用一次当前指向房间的release;然后指向新的房间,调用一次新房间的retain
// >谁创建,谁release(alloc,new,copy);
// >谁retain,谁release(责任);
// >原则:有始有终,负责任
// 多对象内存管理-03-代码演示
#import "Person.h"
#import "Book.h"
int main()
{
Book * b = [[Bookalloc]init];
Person *p1 = [[Personalloc]init];
[p1 setBook:b];
//[b retain]; // p1想占有b这本数,那么调用一次b的retain,这是隐形调用
[b release];
b = nil;
[p1 release];
p1 = nil;
return0;
}
@implementation Person
- (void)setCar:(Car *)car
{
if (car !=_car)//set的car不是当前的才释放旧的,换新的,否则不管
{
//在这里需要对旧车做一次release
[_carrelease];
_car = [car retain];
}
}
- (Car *)car
{
return_car;
}
- (void)setAge:(int)age
{
_age = age;
}
- (int)age
{
return_age;
}
- (void)dealloc
{
[_carrelease];
NSLog(@"personrelease");
[superdealloc];
}
@end
// 内存管理代码规范:
// 1.只要调用了allocation,必须有release(autorelease)
// 2.set方法的代码规范:
// 1>基本数据类型:直接复制
// - (void)setAge:](int)age
// {
// _age = age;
// }
//
// 2> OC对象类型
// - (void)setCar:](Car*)car
// {
// //1.先判断是不是新传进来对象
// if(car !=_car)
// {
// //2.对就对象做一次release
// [_car release];
//
// //3.对新对象做一次retain
// _car = [car retain];
// }
// }
//
// 3.dealloc方法的代码规范
// 1>一定要[superdealloc],而且放在最后面
// 2>对self(当前)所拥有的其他对象做一次release
// - (void)dealloc
// {
// [_car release];
// [super dealloc];
// }
//1.set方法内存管理相关的参数
// * retain: release旧值,retain新值(适用于OC对象类型)
// * assign:直接赋值(默认,适用于非OC对象类型)
// * copy: release旧值,copy新值
//2.是否要生成set方法
//* readwrite:同时生成setter和getter
//* readonly:只会生成getter的声明
//3.多线程管理
//* nonatomic:性能高生成setter方法的时候不要设置多线程
//* atomic: 性能低(默认)//不要用这个
//4.setter和getter方法的名称
2. autorelease与ARC机制
// 2.autorelease的好处
// 1>不用再关系对象释放的时间
// 2>不用再关系什么时候调用release
// 3.autorelease的使用注意
// 1>占用内存较大的对象不要随便使用autorelease
// 2>占用内存较小的对象使用autorelease,没有太大影响
// 4.错误写法
// 1> alloc之后调用了autorelease,又调用release
// 2> 连续多次调用autorelease,具体的各个对象释放时间
// 5.自动释放池
// 1>在ios程序运行过程中,会创建无数个池子.这些池子都是以栈结构存在(先进后出)
// 2>当一个对象调用autorelease方法时,会将这个对象放到栈顶得释放池
// (程序每隔一段时间会自动生成和方法一定数量的池子,通常发生在程序与用户发生交互的时候)
// 6.自动释放池的创建方式
// 1>ios 5.0前
// NSAutoreleasePool *pool= [[NSAutoreleasePool alloc] init];
// [pool release]; // [pool drain]
// 2>ios 5.0开始
// @autorelease{}
// autorelease的应用
#import "Person.h"
// 1.系统自带的方法里面没有包含alloc,new,copy,说明返回的对象都是autorelease的
// 2.开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象
// 1> 创建对象时不要直接使用类,一般用self(为了分类和子类的适应性)
#import "GoodPerson.h"
int main()
{
@autoreleasepool {
Person *p2 = [Person personWithAge:100];
GoodPerson *p = [GoodPerson personWithAge:10];
p.money =100;
}
return0;
}
int test()
{
Person *p = [[Personalloc]init];
p.age =200;
[p release];
@autoreleasepool {
// Person *p2 = [Person person];
//
// p2.age = 100;
// Person *p2 = [PersonpersonWithAge:100];
NSString *str = @"12313132";
NSString *str2 = [NSString stringWithFormat:@"age is %d",10];
NSString *num = [[NSNumber alloc] initWithInt:10];
NSNumber *num2 = [NSNumber numberWithInt:10];
}
return0;
}
//OC里没有包的概念,同名文件即使在不同文件夹中也会认为是同一文件
//在创建对象的时候尽量使用self
// ARC是一个编译器特性,编译器在编译的时候检测哪里需要插release,不是java的垃圾回收.
// 01-ARC-基本原理
// ARC的判断准则:只要没有强指针指向对象,就会释放对象
// 指针分两种
// 1>强直阵:默认情况下,所有的指针都是强指针 __strong
// 2>弱指针:__weak
// ARC-02-@property的strong和weak
// 1.ARC特点
// 1>不允许调用release,retain,rtainCount
// 2>允许重写重写dealloc,但是不允许调用[superdealloc]
// 3>@property的参数
// *strong:成员变量是强指针(使用于OC对象类型)
// *weak:成员变量是弱指针(适用于OC对象类型)
// *assign:适用于非OC对象类型
// 4>以前的retain改为用strong
// ARC-03-Xcode的ARC转换功能
//Xcode-edit-Refactor-transfer to ARC
// 多个文件,某个文件不要ARC,在buildphases里找到对应.m,输入"-fno-obj-arc"即可,相反情况用"-f-obj-arc"
// ARC-04-循环引用
// 之前非ARC里"人-身份证"循环引用问题,"狗-主人"问题
// 1>非ARC1端用retain,另一端用assign
//1>ARC 1端用strong,另一端用weak