您的位置:首页 > 移动开发 > Objective-C

objective-C 编程全解-第05章 基于引用计数的内存管理 中

2016-06-04 11:05 351 查看
5.3 分数计算器的例子

5.3.1 分数类Fraction

5.3.2 保存计算结果的FracRegister类

5.3.3 主函数和执行示例

5.4 ARC概要

5.4.1 什么是ARC

    采用引用计数方式管理内存时需要程序员管理所生成对象的所有权(object ownership)。程序员需要清楚地了解获得/放弃对象所有权的时机,并在适当的地方插入retain、release或autorelease函数。

    ARC(Automatic Reference Counting,自动引用计数)是一种编译期技术。ARC通过在编译期间添加合适的retain/release/autorelease等函数,来确保对象被正确地释放。

    ARC目前只能管理Objective-C的对象,不能管理通过malloc申请的内存。

    下面举例说明ARC是如何工作的:

        现在有一个只想某个对象的变量s,假设将一个w对象赋值给s。

            s=w;

        赋值操作后,s原来指向的对象将不能通过s来访问,s需要放弃该对象的所有权。与此同时,s需要获得新赋值的对象w的所有权。编译以上代码的时候,ARC相当于生成了以下代码。

            [w retain];

            id _old = s;

            s = w;

            [_old release];

        注意没有采用下面的写法:

            [s release];

            s = [w retain];

        这是因为如果把s赋值给他自己,上面的代码可能产生问题。

    为了让对象能够像程序员预先设计的那样被保持或销毁,需要给编译器正确信息。也就是说,程序员在编程时需要遵守一定的规则。

5.4.2 禁止调用引用计数的相关函数

5.4.3 管理自动释放池的新语法

    ARC中禁止使用NSAutoReleasePool,而是使用新语法@autoreleasepool来管理自动释放池。手动管理内存的情况下,自动释放池的使用方法如下:

        id pool = [[NSAutoreleasePool alloc]init];

        /*进行一系列操作*/

        /*此处不可以使用return之类的语句,慎用break、goto之类的语句*/

        [pool release];/*释放对象*/

    新的语法如下所示。

        @autoreleasepool {

            /*进行一系列操作*/

            /*可以使用break,return,goto之类的语句*/

        }

   
旧的写法中不可以使用return之类的语句,慎用break、goto之类的语句否则对象有可能无法被成功释放(如跳过了[pool
release])。

    新的语法中,只要运行到@autoreleasepool块以外的时候,对象就会被release一次,所以可以放心使用break,return,goto之类的语句。

    另外@autoreleasepool在非ARC模式下也能使用,并且使用@autoreleasepool比使用NSAutoReleasePool性能更好效率更高,所以无论是否使用ARC,都推荐使用这种新的语法。

5.4.4 变量的初始化

    在ARC中,未指定初始化的变量(包括局部变量)都会被初始化为nil。

    但是对于_autoreleasing和_unsafe_unretained修饰的变量来说,初始值是未定的。

5.4.5 方法簇

    采用引用计数方式管理内存时,如果不使用alloc/init/new/copy/mutableCopy这些方法、或者不使用retain来保留一个对象,就不能成为对象的所有者。另外、只有使用release或者autorelease,才能够放弃这个对象的所有权。

    这些规定被叫做所有权策略(ownership policy。换句话说,对象实例该由谁来释放,并不取决于编程语言方面的要求,而是有编程逻辑决定的。

    另一方面,由于ARC允许混合链接手动内存管理和自动内存管理的代码,所以针对到底哪个方法同对象的生成和复制相关这一问题,需要使用能够让编译器明确区分的方法。同对象生成相关的方法集合叫做方法簇(method
family)。

    一个方法要属于某个方法簇,除了要满足返回值和方法的类别(类方法还是实例方法)方面的需要外,也需要满足以下命名规则,即选择器同方法簇名相同(开头的_可忽略),或选择器的名字有方法簇名加上非小写字母开头的字符构成。

    例如,以下选择器符合init方法簇的要求

        init

        initToMemory

        initWIthData:

        _init:local:

    而以下这些选择器则不符合要求。

        initialize  
--init的后面能接小写字母

        do_initWithData:
--不以init开头

    目前为止有5个方法簇。其中可被保持的对象(retainable
object)指的是Objective-C的对象或block对象。

        alloc方法簇

        copy方法簇

        mutableCopy方法簇

        new方法簇

    以上四个方法簇
中的方法表示调用则对被常见的对象拥有所有权,返回的对象必须是可以被retain的。

        init方法簇

   
以init开头的方法比簇必须定义为实例方法(alloc出一个对象时,这个对象的引用计数已经是1了),它一定要返回id类型或父类、子类的指针。

    以init开头的方法之外,以alloc/new/copy/mutablecopy开头的方法都既可以是类方法也可以是实例方法。依照Objective-c中的命名惯例,调用以alloc/new/copy/mutablecopy/init开头的方法时,需要将对象所有权返回给调用端,由调用端release生成的对象。另一方面,如果你想由调用端来release一个方法返回的对象,而这个方法的名字又不是以上关键字开头的话,ARC就有可能不会释放这个对象,从而造成内存泄漏。

给方法命名时必须遵循命名规则。大家可能会无意中使用new或copy开头的名字作为方法名,例如给一个换行的方法命名为newLine,给一个获取版权的方法命名为copyRight等。这些命名都是不正确的,有可能造成释放,也可能在编译时提示警告或错误。因此要切记严守内存管理相关的函数命名规则。

5.4.6 方法dealloc的定义

    ARC编程的时候不能显式调用dealloc方法,包括使用@selector(dealloc)等的隐式调用。

    重写dealloc时也不需要调用父类的dealloc方法。

    举例如下:

        (a)类MyBuffer的接口

            @interface MyBuffer:NSObject

            {

                NSString *filename;

                NSView *monitorView;

                char    *buffer;

                FILE   *fp;

            }

            …

        (b)手动管理内存方式下dealloc的实现

            -(void)dealloc

            {

                [filename release];

                [monitorView release];

                if(buffer != NULL)

                {

                    free(buffer);

                }

                if(fp != NULL)

                {

                    fclose(fp);

                }

                [super dealloc];

            }

        (c)ARC有效时的dealloc的实现

            -(void)dealloc

            {

                if(buffer != NULL)

                {

                    free(buffer);

                }

                if(fp != NULL)

                {

                    fclose(fp);

                }

            }

5.4.7 使用ARC的程序的编译

    启用ARC编译代码时,不能使用gcc而要使用clang。同时,通过-fobj-arc可以设置使用ARC,通过-fno-obj-arc来明确告诉编译器不想使用ARC。

    使用ARC的代码可以与不使用ARC的代码混合链接。

5.4.8 ARC的基本注意事项

   
1:不能在程序中定义和使用下面这些函数:retain、release、autorelease和retainCount。

   
2:使用@autorelease代替NSAutoreleasePool。

    3:方法命名必须遵循命名规则,不能随意定义以allocinitnewcopymutableCopy开头且和所有权操作无关的方法。

    4:不用在dealloc中释放实例变量(但可以在dealloc中释放资源),也不需要调用[super
dealloc]。

    5:编译代码时使用编译器clang,并加上-fobj-arc

5.4.9 使用ARC重构分数计算器
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: