A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 池莉娘子 中级黑马   /  2015-7-9 13:56  /  783 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

内存管理
   每个对象内部都有自己的引用计数器,是一个整数,表示对象被引用的次数,占用四个字节的存储空间。当这个引用计数器为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操作

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马