内存管理
每个对象内部都有自己的引用计数器,是一个整数,表示对象被引用的次数,占用四个字节的存储空间。当这个引用计数器为0的时候,这个对象占用的内存就会被系统回收,对象变成僵尸对象。僵尸对象就是指占用内存被回收的对象。当我们创建一个对象时,这个引用计数器的值默认是1.
引用计数器的操作
1. retain操作:使计数器值+1
2. release操作:使计数器值-1
3. retainCount操作:返回计数器的值
当一个对象被销毁时,对象会调用dealloc方法,被销毁的对象会变成僵尸对象。所以一般我们在对象被销毁时会重写dealloc方法,判断对象是否被释放,在这里我们也可以释放相关资源,如占用的其他对象;但是注意dealloc方法不是主动去调用的,它是对象被销毁时系统自动调用的,重写dealloc方法时,还必须要调用[super dealloc];方法,并且要放在最后,如下
@implementation Person
- (void)dealloc
{
NSLog(@"Person对象被释放");
[super dealloc];
}
@end
下面来通过一个具体的例子来看看怎么释放对象:
简单描述:每个人都有一本书,所以我们需要两个类
* Person类属性:Book *_book;
* Book类
Perosn.h文件
# import <Foundation/Foundation.h>
# import "Book.h"
@interface Person : NSObject
{
Book *_book;
}
- (void)setBook:(Book *)book;
- (Book *)book;
@end
Person.m文件
#import "Person.h"
@implementation Person
- (void)setBook:(Book *)book
{
if(_book != book) // 判断传进来的对象是不是原来的对象,不是的时候才执行下面语句,防止反复传入同一个对象
{
[_book release]; // 将上一个传进来的对象解除占用,因为如果不解除占用,它的计数器一直都是1
// 如果没有判断,当再次传入同一个对象时,会导致下面这句报错,book指向僵尸对象
_book = [book retain]; // 给新传进来的book对象中的引用计数器值+1,retain方法返回对象本身
}
}
- (Book *)book
{
return _book;
}
- (void)dealloc
{
[_book release];// 在自己被释放的时候要将被自己占用的_book对象的引用计数器的值-1
[super dealloc];// 重写dealloc方法时,要在最后写上这句代码
}
@end
Book.h文件
# import <Foundation/Foundation.h>
@interface Book : NSObject
{
int _price;
}
- (void)setPrice:(int)price;
- (int)price;
@end
Book.m文件
#import "Book.h"
@implementation Book
- (void)setPrice:(int)price
{
_price = price;
}
- (int)price
{
return _price;
}
- (void)dealloc
{
NSLog(@"Book对象被释放");
[super dealloc];
}
@end
main.m文件
int main()
{
Person *p = [[Person alloc] init]; // 创建对象引用计数器值默认是1,有对象创建就有一次release(注意后面)
Book *b = [[Book alloc] init];
[p setBook:b]; //Person对象使用了Book对象,这时要调用retain方法
[b release];
b=nil; // 将野指针变空指针
[p release]; // 对应于对象创建
//在Person对象被释放的时候,Book对象同时被释放
p=nil;
/*
上面代码是先回收b指针,取消b和Book对象的联系,但是Book对象还是存在,并没有释放掉,释放的操作是在释放Person对象的时候执行的;但是如果把[b release];和[p release];的顺序换一下,就是先把Person释放掉,Book对象还在,最后是在执行[b release];的时候释放掉Book对象的,再把b赋为空指针
*/
return 0;
}
通过上面的实例我们可以总结出内存管理的一些规范
1.只要调用了alloc,就要调用release,只要有retain,就要有release
2.set代码规范
1>基本数据类型:直接赋值
- (void)setPrice:(int)price
{
_price = price;
}
2>OC对象类型
- (void)setBook:(Book *)book
{
if(book != _book) // 判断传进来的对象是不是原来的对象,不是的时候才执行下面语句,防止反复传入同一个对象
{
[_book release]; // 将上一个传进来的对象解除占用,因为如果不解除占用,它的计数器一直都是1
// 如果没有判断,当再次传入同一个对象时,会导致下面这句报错,book指向僵尸对象
_book = [book retain]; // 给传进来的book对象中的引用计数器值+1,retain方法返回对象本身
}
}
3.dealloc代码规范
1>一定要写[super dealloc];且一定要放在最后
2>对所占有对象作release操作
|
|