OC--内存管理
栈:主要存储局部变量 (基本类型,指针,枚举等)
堆:主要存储动态变量 (对象)
注意:NNString * id是一个对象//(NNString *) name;
什么是内存管理
* 移动设备的内存极其有限,每个app所能占用的内存是有限制的
* 当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间。比如回收一些不需要使用的对象、变量等
* 管理范围:任何继承了NSObject的对象,对其他基本数据类型(int、char、float、double、struct、enum等)无效
对象的基本结构
* 每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象
* 每个OC对象内部专门有4个字节的存储空间来存储引用计数器
引用计数器的作用
* 当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1
* 当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,
除非整个程序已经退出
计数器方法的基本使用
1、 retain:计数器+1,会返回对象本身 [p retain];
2、 release:计数器-1,没有返回值 [p release];
3、 nil: 清空指针,使指针变为空指针p = nil;
4、 retainCount:获取当前的计数器值
5、 dealloc://类似于遗言,一般会重写
*当一个对象要被回收的时候,就会被调用
*一定要调用[super dealloc],这句调用要放到最后面
- (void)dealloc
{
/*
_speed 为成员变量
_speed :直接访问成员变量
self -> _speed:直接访问成员变量
self .speed:get方法
self speed:get方法
*/
NSLog(@"速度为%d的Car对象被回收啦",self -> _speed);
[super dealloc ];
}
概念
1、僵尸对象:所占用内存已经被回收的对象,僵尸对象不能再使用
2、野指针:指向僵尸对象(不可用内存)的指针,
给野指针发送消息会报错,错误形式为:EXC_BAD_ACCESS
3、空指针:没有指向任何东西的指针(存储的东西是nil,null,0),
给空指针发送消息不会报错
开启僵尸对象监控
默认情况下,Xcode是不会管僵尸对象的,使用一块被释放的内存也不会报错。为了方便调试,应该开启僵尸对象监控
对象的销毁
* 当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收
* 当一个对象被销毁时,系统会自动向对象发送一条dealloc消息
* 一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言
* 一旦重写了dealloc方法,就必须调用[superdealloc],并且放在最后面调用
* 不要直接调用dealloc方法
* 一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)
多对象内存管理
1、你想使用(占用)某个对象,就应该让对象的计数器+1(让对象做一次retain操作)
2、你不想再使用(占用)某个对象,就应该让对象的计数器-1(让对象做一次release)
3、谁retain,谁release [对象 retain]; [对象 release];
4、谁alloc,谁release [[对象 alloc] init]; 最后还有dealloc
总之:一个对象有多少相关,就必须释放多少次
Set方法的内存管理
内存管理代码规范:Person对象拥有Car对象
1、 只要调用了alloc,必须有release(autorelease)
如果对象不是alloc产生的,就不需要写release
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 = [carretain ];
}
}
3、 dealloc方法的代码规范(不要自己接调用dealloc)
1> 一定要[super dealloc],而且放到最后面
2> 对self(当前)所拥有的其他对象做一次release
- (void)dealloc
{
[ _car release ];
[super dealloc];
}
Set方法内存管理--@property的参数
格式:@peoperty (参数) 类型 名称;
1、 Set方法内存管理相关参数
* retain:release旧值,retain新值(适用于OC对象类型)
* assign:直接赋值(默认,适用于非OC对象类型)
* copy:release旧值,copy新值
2、是否要生成set方法
* readwrite:同时生成setter和getter的声明,实现(默认)
* readonly:只会生成getter的声明和实现
3、多线程管理
* nonatomic:性能高(一般就用这个)
* atomic:性能低
4、setter和getter方法的名称
* setter:决定了set方法的名称,一定要有冒号:
* getter:决定了get方法的名称(一般用在BOOL类型:
BOOL类型的方法名称一般以is开头)
@property的用法
@property(nonatomic,retain) 对象类型名称;一定要记得在最后的dealloc中[_名称 release]
@property(nonatomic,assign) 基本类型名称;
循环调用对象@class:@class能提高性能
1、@class的作用:仅仅告诉编译器,某个名称是一个类
@class Person; // 仅仅告诉编译器,Person是一个类
2、 开发中引用一个类的规范
1> 在.h文件中用@class来声明类,写在@interface之前
2> 在.m文件中用#import来包含类的所有内容
3、 两端循环引用解决方案
一端用retain,一端用assign
4、@class和#import的区别
l #import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在A.h文件中 B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息
l 如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来讲,使用@class方式就不会出现这种问题了
l 在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类
@autoreleasepool { } 自动释放池
1、 autorelease的基本用法:
1>书写形式:Book *book = [[[Bookalloc]init]autorelease];
1>会将对象放到一个自动释放池中
2>当自动释放池销毁时,会对池子里面所有的对象做一次release
3>会返回对象本身
4>调用完autorelease方法后,对象计数器不变
2、 autorelease的好处
1> 不用再关心对象释放的是时间
2> 不用再关心什么时候调用release
3、autorelease的坏处
1> 占用内存比较大的对象不要随便使用autorelease
2> 占用内存比较小的对象使用autorelease,没有太大影响
4、错误写法(野指针错误):注意
1> 在@autoreleasepool池子中,调用一次alloc,然后autorelease一次之后,
又调用一次release
2> 在@autoreleasepool池子中,调用一次alloc,然后调用两次autorelease
5、自动释放池
1> 在ios程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)
2> 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
6、自动释放池创建方式
ios5.0后
@autoreleasepool
{
// ....
}
ios 5.0前
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// .....
[pool release]; // 或[pool drain];
/*
1.系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelease的
2.开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象
1> 创建对象时不要直接用类名,一般用self
+ (id)person
{
return [[[self alloc] init] autorelease];
}
ARC 编译器特性(自动生成代码)
ARC的判断准则:
1、 ARC特点:
1> 不允许调用release, retain, retainCount
2> 允许重写dealloc,但不允许调用[super dealloc ]
3> @property的参数,位置和retain一样
*strong:成员变量强指针 (适用于OC对象类型)
*weak:成员变量弱指针 (适用于OC对象类型)
*assign:适用于非OC对象类型
4> 以前的retain 改为 strong
指针分两种:
1> 强指针:默认情况下,所有指针都是强指针 _ _strong
* 有强指针指向的对象,ARC不会回收
2> 弱指针:_ _weak
*弱指针指向的对象,ARC会回收该对象,并回收掉弱指针
当两端循环引用的时候,解决方案:
1>ARC
一端用strong,另一端用weak
2>非ARC
一端用ratain,另一端用assign
怎么把原来不是ARC的项目改为ARC项目
1、选中项目,打开如图状态(如图 1)
2、然后直接点下一步,中间会有一个预览(左侧为ARC,右侧为源文件的对比)(如图 2)
怎么看项目是不是ARC
1 点击项目 (如图 3)
2 点击BuildSettings 找到放大镜
3 在放大镜里搜索Auto,显示如图1
4 然后找的Xcode对应的版本,看Object-C ARC后面,如果是Yes,则表明项目开启了ARC模式
设置文件是否用ARC
如图 4,打开到这里,具体步骤参考前面
1 点击Build Phases
2 点开下面的第二个 Compile。。。
3 选中要更改的文件,
4 按enter 打开如图小窗口,
5 在小窗口中输入对该文件的设置
( – fno-objc-arc :表示不用ARC, – fno-objc-arc :表示用ARC)