内存管理简介和要点
为什么要管理内存?
- iOS应⽤用程序出现Crash(闪退),90%的原因是因为内存问题。
- 在一个拥有数十个甚⾄至是上百个类的工程⾥里,查找内存问题极其困难,学会内存管理,能帮我们减少出错的几率。
- 内存问题体现在两个⽅方面:内存溢出、野指针异常。
- 常见Crash原因:内存溢出,野指针异常
内存管理方式
- 垃圾回收机制(Garbage-Collection)。
- MRC(Manual Reference Counting)。
- ARC(Auto Reference Counting)。
//垃圾回收机制:程序员只需要开辟内存空间,不需要用代码的形式释放,系统来判断哪些空间不再被使用,并回收这些内存空间,以便再次分配。整个回收的过程不需要写任何代码,由系统自动完成垃圾回收。Java开发中一直使用的就是垃圾回收技术。
//Manual Reference Counting 人工引用计数:内存的开辟和释放都由程序代码进行控制。相对垃圾回收来说,对内存的控制更加灵活,可以在需要释放的时候及时释放,对程序员的要求较高,程序员要熟悉内存管理的机制。
//Auto Reference Counting 自动引用计数:iOS 5.0的编译器特性,它允许用户只开辟空间,不用去释放空间。它不是垃圾回收!它的本质还是MRC,只是编译器帮程序员默认加了释放的代码。
- iOS支持两种内存管理方式:ARC和MRC。
- MRC的内存管理机制是:引用计数。
- ARC是基于MRC的。
引用计数(Retain)
- OC采用引用计数机制管理内存,每个对象都有⼀个引用计数器,用来记录当前对象的引用次数。
- 当一个新的引用指向对象时,引用计算器加1,去掉引用时,引用计数减1.
- 当引用计数为0时,该对象的空间就被系统回收.
- retainCount获取对象的引⽤用计数。
OC对象的操作 OC中对应的方法
生成对象 +alloc
持有对象 -retain
释放对象 -release/-autorelease
销毁对象 -dealloc
影响引用计数的方法:
- +alloc 开辟内存空间,引用计数从0变1
- -retain 引用计数加1
- -copy 对某对象内存拷贝出新的对象,原对象引用指针不变,新对象引用指针变1
自动释放池
- 通过autoreleasepool自动释放池,空值autorelease对象的释放
@autoreleasepool{ //自动释放池创建
}//自动释放池销毁
内存管理原则
当使用new、alloc或copy方法创建一个对象时,该对象引用计数器为1。如果不需要使用该对象,可以向其发送release或autorelease消息,在其使用完毕时被销毁。
• 如果通过其他方法获取一个对象,则可以假设这个对象引用计数为1,并且被设置为autorelease,不需要对该对象进行清理,如果确实需要retain这个对象,则需要使用完毕后release。
• 如果retain了某个对象,需要release或autorelease该对象,保持retain方法和release方法使用次数相等。
使用new、alloc、copy关键字生成的对象和retain了的对象需要手动释放。设置为autorelease的对象不需要手动释放,会直接进入自动释放池。
Protocol(协议)
- 协议中的方法默认为必须实现(required),@optional 修饰方法为可选择实现
- 协议分正式协议和非正式协议
协议六步:
#warning 第一步,声明协议
#warning 第二步,声明代理
#warning 第三步,让代理人去执行协议方法
#warning 第四步,遵循协议
#warning 第五步,设置代理人(谁来执行协议方法)
#warning 第六步,实现协议方法
如同开淘宝提供平台给所有人卖商品,商家需要接受协议才可买东西
浅拷贝和深拷贝区别是什么?
浅层复制:只复制指向对象的指针,而不复制引用对象本身。
深层复制:复制引用对象本身。
浅复制好比你和你的影子,你完蛋,你的影子也完蛋
深复制好比你和你的克隆人,你完蛋,你的克隆人还活着。
KVC
1、KVC简介
全称是Key-value coding,翻译成键值编码。顾名思义,在某种程度上跟map的关系匪浅。它提供了一种使用字符串而不是访问器方法去访问一个对象实例变量的机制。
2、KVO简介
全称是Key-value observing,翻译成键值观察。提供了一种当其它对象属性被修改的时候能通知当前对象的机制。再MVC大行其道的Cocoa中,KVO机制很适合实现model和controller类之间的通讯。
//KVC - KEY VALUE CODING 键值编码
//使用KVC间接对实例变量赋值
[per setValue:@"haha" forKey:@"name"];
//KVC取值
NSLog(@"%@",[per valueForKey:@"name"]);
- Key Value Coding,键值编码
- 使用字符串(Key)间接访问对象实例变量的机制
类.m文件中
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
//使用KVC必须写这个方法,作用是当找不到对应方法执行这个方法,防止CRASH
}
ARC
- 当工程开启ARC后,由于编译器会自动帮你释放内存,所有和内存相关的操作retain,release,autorelease,都不能写
- 当重写dealloc方法时,也不能写[super dealloc],否则会报错
类.h中
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property(nonatomic,copy) NSString *name;
@property(nonatomic,retain) NSString *gender;
@end
类.m中
#import "Person.h"
@implementation Person
//ARC下管理,防止内存泄露(指针指向别的对象或指针的引用计数为0,原对象引用计数大于0并存在)
-(void)setName:(NSString *)name{
if (_name != name) {
[_name release];
_name = [name copy];
}
}
-(NSString *)name{
return [[_name retain]autorelease];
}
@end
- 特定文件打开ARC
- 打开ARC : -fobjc-arc
- 关闭ARC : -fno-objc-arc
一些实用用法(有用)
//多个变量赋值时可使用字典(有用)
Person *per1 = [[Person alloc]init];
NSDictionary *dic = @{@"name":@"zh",@"gender":@"未知"};
[per1 setValuesForKeysWithDictionary:dic];
Teacher *t = [[Teacher alloc]init];
Person *per2 = [[Person alloc]init];
[per2 setValue:t forKey:@"teacher"];
[per2 setValue:@"小炮" forKey:@"teacher.name"];
NSLog(@"%@",[per2 valueForKeyPath:@"teacher.name"]);
学习总结
- OC借助引用计数机制去管理内存,凡是使用了alloc、copy、retain等方法,增加了引用计数,就要使用release和autorelease减少引用计数,引用计数为0的时候,对象所占的内存,被系统回收。
- autorelease是未来某个时间(autorealease销毁)引用减一,不是即时的。
- 不是任何对象都可以接收copy消息,只有接受了NScoding协议的对象才能接收copy消息。
- assign,retain,copy对应不同的release实现。为实例变量赋值时,尽量使用release方法,再次赋值时,会把之前值release。
- dealloc在对象引用计数为0时自动调用,不要显示调用。
- dealloc实现内部,先要释放实例变量,然后执⾏行[super dealloc]。
- 便利构造器的内存管理是借助autorelease实现的。
- 集合会管理自己的元素。
- KVC是一种间接访问实例变量的⽅方法。
- ARC系统管理内存,不需要开发人员手动管理。