OC(七)内存管理
一.ios的app使用的内存超过30M,则系统会向改app发送Memory Warning消息,收到消息,他必须正确处理,负责可能出现内存泄露甚至崩溃。
对象是要占用内存的,如果创建了对象(分配了内存)而不去释放这些对象所占用的内存,将会发生内存泄露。
需要手动去管理内存。
管理内存:
1.分配内存
2.释放内存
在不需要这个对象的时候,及时把这个对象释放掉,就可以防止内存泄露(只分配,不释放)。
不知道怎么去判断是否需要释放一个对象
引用计数:是判断一个对象是否存在的一个标准
得到引用计数公式:对象名.retainCount
什么样的数据需要咱们手动管理内存?
基本数据类型(不能称之为对象,不具备对象的属性特征,只是一个单一的数据)不需要咱们手动管理内存,它由系统处理 ->栈
除了基本数据类型,都需要手动管理内存(需要程序员管理) ->堆
程序员开辟的内存,属于分配到堆里,系统自动分配的内存会到栈里。
person *p = [[person alloc]init]; 堆
int a = 10; 栈
谁分配谁释放
retainCount 引用计数>0的时候,就是对象存在的时候,如果不大于0,就表示这个对象已经被释放了.
二. 生命周期
1.alloc之后对象就存在了
2.具体对对象的操作
3.释放对象
引用计数的操作:
引用计数是判断一个对象是否存在的一个标准(>0)
*******重要********
让引用计数+1的方法:
①.alloc、new
②.retain 保留引用计数
③.copy
让引用计数-1的方法:
①.release 释放
②.autorelease 延迟释放
对象被释放的时候会调用一个销毁对象的方法--delloc->销毁对象
有一个alloc、retain、copy就要有一个对应的release,才能释放掉对象。
MRC:手动管理引用计数
ARC:自动管理引用计数
setter方法的内存管理
- (void)dealloc{
[super delloc];
[原来的变量(全局变量) release];
}
- (void)set对象名:(类型)参数名{
if (原来的变量 != 参数名){
[原来的变量 release];
原来的变量 = [参数名 retain];
}
}
内存管理的原则:谁分配谁释放
有一个alloc retain copy 就要有对应的release autorelease
引用技数:retaincount
引用计数+1:alloc retain copy
引用计数-1:release autorelease
copy 会产生一个新的对象,新的对象引用计数+1,跟原来对象没有关系
如果释放了原来的对象,新的对象依然存在
retain 保留引用计数,给原来对象引用计数+1,只要有一个引用计数为0,这个对象就会被销毁掉。
autorelease:延迟释放 等到需要释放时才去释放,也会引用计数-1
常与自动释放池配合使用
自动释放池:在自动释放池里面的对象,只要使用了outorelease 在出池的时候就会被统一释放掉
自动释放池的两种写法:
1、@autoreleasepool {
花括号内表示在自动释放池内
}出了花括号就表示出池(所有使用autorelease的对象全部会被释放掉)
2、NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
只要在自动释放池对象release之前都算池内
[pool release];
属性的ARC关键字的声明
属性手动管理引用计数:
ARC:自动管理引用计数
MRC:手动管理引用计数
//自动释放池的生命周期
//当对象在自动释放池被创建,并使用auyorelease
//对象会在自动释放池出池的时候,被自动释放池统一调用池内全部的autorelease 释放全部对象
//可以使用在循环创建一些对象的时候,不知道什么时候创建使用完毕,可以选择使用自动释放池
@autoreleasepool {
// Person *laoWang = [[[Person alloc]init]autorelease];
/* Person *person = [[Person alloc]init];
// Person *person = [Person new];
[person retain];
//retain 给同一对象保留引用计数
//目的 为了保证一个不会被释放掉,给这个对象引用计数+1
Person *ppp = [person retain];
NSLog(@"%ld",ppp.retainCount);
[person release];
NSLog(@"%ld",person.retainCount);
//打印结果:内存管理[1263:49394] 2
//打印结果:内存管理[1263:49394] 1
[person release];
//打印结果:对象已经被销毁
//如果一个对象被释放掉 这个对象就是野指针(指针跟对象都存在着,但是联系不起来了),为了防止使用野指针可以在这个对象释放之后,同时给这个对象赋值为空(nil)
person = nil;
*/
//
// Person *person = [[Person alloc]init];
// Person *pp = [person retain];
// [person release];
// [pp release];
// Weapon *qiang = [[Weapon alloc]init];
// Person *huluiwa = [[Person alloc]init];
// [huluiwa setWeapon:qiang];
// [qiang release];
//如果现在释放qiang huluwa这个对象还在使用 就得想办法让qiang不被销毁
//方法:+1,在setWeapon这个方法中
//在dealloc方法中销毁qiang
// NSLog(@"%@",huluiwa.weapon);
// [huluiwa release];
// NSArray *list = [[NSArray alloc]initWithObjects:@"1111", nil];
// NSArray *list2 = [list copy];
// //nil 存在的对象也可以置空
// [list release],list = nil;
// NSLog(@"%@",list2);
// [list2 release];
NSMutableArray *list = [NSMutableArray array];
//作用域不放入自动释放池
/* @autoreleasepool {
for (int i=0; i<10; i++) {
Person *p = [[[Person alloc]init]autorelease];
[list addObject:p];
}
}*/
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
for (int i=0; i<10; i++) {
Person *p = [[[Person alloc]init]autorelease];
[list addObject:p];
}
[pool release];
------.h----------
{
Weapon *_weapon;
}
-(void)setWeapon:(Weapon *)weapon;
-(Weapon *)weapon;
//在字符串、数组、字典、为属性的一般都是用copy
//其他对象都是使用retain
@property (nonatomic,copy)NSString*name;
//基本数据类型使用assign(直接赋值)
//属性其他关键字
//1.只读:readonly只允许访问 不允许修改(只允许使用getter方法)
//2.读写:readwrite
//3.getter=isSuccess 表示在赋值的时候,这个属性叫做success 在取值的时候叫做isSuccess
//1.retain:只要使用属性 除了基本数据类型 都可以使用retain
//2.copy:在字符串、数组、字典、为属性的一般都是用copy
//是为了防止赋值的数组被释放置空,影响属性的数组,生成一个新的数组
//3、assign 是直接赋值 只要是基本数据都是用assign
//设置属性的访问权限
//readwrite:开放属性的全部权限
//readonly:只开放读取的权限(保护对象里面的数据不被修改)
//ARC:
//1.strong强壮的 不会被释放调用<告诉系统这个属性是不能被释放的>
//2.unsafe_unretained 允许在特殊情况下释放掉,不安全的
-------------.m----------
//重写(父类方法子类再写一次)
//优先调用子类重写父类的方法
//如果子类还想实现父类同样的功能
- (void)dealloc
{
//具体销毁对象的内容
//当引用计数为0的时候会自动调用这个方法
//当人被销毁的时候也就是不再需要武器的时候,就可以销毁
[_weapon release],_weapon = nil;
NSLog(@"对象已经被销毁");
[super dealloc];
}
-(void)setWeapon:(Weapon *)weapon{
//咱们可以确定 person这个对象什么时候被销毁
//可以在销毁这个对象的同时销毁武器
if (_weapon != weapon) {
_weapon = [weapon retain];
}
}
-(Weapon *)weapon{
return _weapon;
}