移动设备的内存极其有限,每个app所能占用的内存是有限制的.当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间。比如回收一些不需要使用的对象、变量等。基本的数据类型是放在内存的栈里面,这是不需要我们去管理的,系统会自动回收。但是我们动态分配的内存是在内存的堆里面,这些都是需要我们去管理的,每个对象都应该有着生命周期,从创建的那一刻,就应该有着它凋亡的时候。
@property和@synthesize关键字
@property和@synthesize关键字可以帮助我们构造属性的设置和访问方法即setter和getter方法,可以省去我们很多重复机械的代码。
在声明文件中使用 @property 声明变量,在实现文件中用@synthesize
@property 关键字可以自动生成某个成员变量的setter和getter方法的声明
@property int age;
编译时遇到这一行,则自动扩展成下面两句:
- (void)setAge:(int)age;
- (int)age;
@synthesize age=_age;
相当于下面的代码:
-(void)setAge:(int)age
{
_age=age;
}
-(int)age
{
Return _age;
}
在新的版本里面@synthesize被抛弃不用了,只要在声明文件里面使用@property声明了变量,那么在实现文件中就不需要用@synthesize了,也能够生成属性的getter和setter方法的实现。
@property关键字的参数介绍
1.控制set方法的内存管理
retain : release旧值,retain新值(用于OC对象)
assign : 直接赋值,不做任何内存管理(默认,用于非OC对象类型)
copy : release旧值,copy新值(一般用于NSString *)注:对象进行深拷贝,原来的对象进行release操作
2.控制需不需生成set方法
readwrite :同时生成set方法和get方法(默认)
readonly :只会生成get方法
3.多线程管理
atomic:性能低(默认)
nonatomic :性能高(一般会使用此参数)
4.控制set方法和get方法的名称
setter : 设置set方法的名称,一定有个冒号:
getter : 设置get方法的名称
不同类型的参数可以同时使用,同类型的只能使用一个
声明property的语法为:@property (参数1,参数2) 类型 名字
@property (nonatomic,retain) Person *p;
计数器的引入
每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象
每个OC对象内部专门有4个字节的存储空间来存储引用计数器
对象的结构图:
计数器的作用
当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1
当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已经退出
计数器的操作
给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)
给对象发送一条release消息,可以使引用计数器值-1
可以给对象发送retainCount消息获得当前的引用计数器值
对象的销毁
当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收
当一个对象被销毁时,系统会自动向对象发送一条dealloc消息
一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言
一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用
不要直接调用dealloc方法
一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)
内存管理法则
谁创建,谁release
如果你通过alloc、new或[mutable]copy来创建一个对象,那么你必须调用release或autorelease
换句话说,不是你创建的,就不用你去[auto]release
谁retain,谁release
只要你调用了retain,无论这个对象是如何生成的,你都要调用release
方法的内存管理
如果你有个OC对象类型的成员变量,就必须管理这个成员变量的内存。
1. set方法的实现
- (void)setBook:(Book *)book{
if (book != _book) {
[_book release];
_book = [book retain];
}
}
2. dealloc方法的实现
- (void)dealloc {
[_book release];
[super dealloc];
}
若在成员变量声明的时候使用了retain参数就不需要写setter方法了。
例如:
@property (nonatomic,retain) Book *book;
循环引用
当A、B类相互引用时,会占据着对象让两个对象都无法得到释放。而且直接两个头文件中相互包含编译器会报错的。
在头文件里面使用@class 来声明A、B是类,在实现文件里面用到了哪个就导入其头文件。
解决内存占据不释放的方法:@property关键字一段用retain 另外一端用 assign
autoreleasepool 和autorelease
autoreleasepool
自动释放池,管理池子中的对象
autorelease
给对象发送autorelease消息时,会将对象存入autoreleasepool,当系统执行完自动释放池时,自动释放池会自动清空池子里边的对象
【注】自动释放池类似于一个数组,进行延迟释放,不会马上计数器减一,而是将当前对象放入最近的自动释放池中,当释放池释放的时候将池中每一个元素都释放一次
自动释放池有着诸多的限制,内存开销过大的不宜使用,但它的存在让我们可以不用怎么太过于注意对象的release时间。
Person *p = [[[Person alloc] init] autorelease];