iOS编程基础-OC(四)-内存管理(续)

 

该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动!


本节接着介绍内存管理相关的内容;


第4章 内存管理


4.4 使用自动引用计数

     

     在使用MRR内存管理方式时,你会亲自管理程序中对象回收工作;

         好处是可以精细地控制内存的使用情况;

         坏处是大幅度增加了开发人员的负担;

     

     因此,手动引用计数更容易出错,会导致程序泄漏内存或崩溃;最好能使用工具完成这类基本任务;

     

     自动引用计数(ARC):

         是一种功能强大的内存管理工具,是这类任务自动化;

         ARC使用引用计数的模式与MRR使用的相同,但是由编译器管理回收对象的工作;

     

     具体的:

         在编译程序时,编译器会分析源代码,确定以动态方式创建的对象的回收需求,然后在已编译代码的必要位置自动插入retain和release消息;

         APR还可以(潜在地)提升应用的性能和消除内存管理错误(如错误释放仍在使用的对象、保留不再使用的对象);

         此外,和垃圾回收机制相比,ARC更可靠(保留和释放语句是在编译时插入的),并且不会为实现垃圾回收机制而在程序执行过程中引入暂停操作;

     

     ARC可以为OC对象和块提供自动内存管理功能;

         注意,ARC无法自动处理循环引用;

         为此,OC提供了弱引用功能,在必要时通过该功能你可以手动解消循环引用;

     

     4.4.1 使用ARC的规则和约定

     

     与MRR相比,ARC可大幅度简化内存管理工作;

     使用ARC时应遵守规则:

     1)不能手动编写发送retain、retainCount、release、autorelease和dealloc消息的代码;

         ARC不允许手动方式控制对象的回收工作;

         如果需要管理实例变量之外的资源,可以手动编写dealloc方法(比如注销通知);

         ARC在您没有在类中编写dealloc方法的情况下,会自动创建该方法,释放其中的对象,并调用父类的dealloc方法;

         在类中编写dealloc方法的情况下,是不能再调用[super dealloc]的;

     

     2)不能直接进行id和(void *)类型的互转;

         ARC只能管理OC对象和块,因此编译器只能处理能够识别出其类型的对象;

         因为(void *)类型的指针是能够转换为任何指针类型(包括OC中没有的指针类型)的通用指针;所以必须设置这个限制;

         当使用Foundation框架对象和Core Foundation对象(一种提供C语言API的Apple软件库)互相转换类型时,此种情况较常见,会有相应的API供在ARC和非ARC环境之间进行变量所有权的转移;

     

     3)需要使用自动释放池代码块执行由ARC管理的自动释放操作;

     4)不能调用Foundation框架函数NSAllocateObject和NSDeallocateObject;

         这两个函数提供了在指定内存区域为对象分配和释放内存的功能;因为OC不再支持内存区,所以无法使用它们;

     

     5)无法使用C结构中的对象指针;

         ARC不能为动态分配的C结构执行内存管理操作,因为编译器无法判断何时应插入必需的retain和release消息;

     

     6)不能使用内存区(NSZone);如前所述,OC不再支持内存区;

     7)为了与非ARC代码协作,不能创建以copy开头的方法和自动声明属性(除非明确定义了其他读取器);

     8)默认情况下,ARC并非异常安全的;

         无法释放异常失效的__strong变量;

         无法在完整表达式抛出异常时,将位于该完整表达式末尾的对象释放;

         使用编译器选项-fobjc-arc-exceptions可以启动处理ARC代码异常的功能;除非编译器解决了该异常,否则当弱引用异常失效时,ARC肯定会释放弱引用变量;

     

     上边都是一些规则,有的比较难懂,在不断学习和成长中,慢慢体会吧;

     

     4.4.2 ARC的声明周期限定符

     

     OC提供了一系列专用的ARC限定符,使用它们可以声明常规变量和属性的生命周期;

     

     应用于常规变量的限定符:

     1)__strong:

         表明使用任何alloc/init消息创建的对象都会在其作用范围内被保留;

         “作用范围”通常是指变量声明所在花括号对的内部(如方法、循环、条件语句块);

         这是常规变量的默认设置;

     

     2)__weak:

         表明对象随时都可以被释放;

         只有当对象拥有其他强引用时,该标记才会有用处;(因为weak是弱引用)

         对象被释放之后,待__weak限定符的变量会被设置为nil;

     

     3)__unsafe_unretained:

         与__weak限定符类似,但是在对象被释放后,指针不会被置为nil,而是处于悬空状态(不再指向合法对象);

         所以是不安全的 也不会获得对象的所有权的;

     

     4)__autoreleasing:

         不要将该限定符与调用对象中的autorelease方法搞混了,这个限定符用于通过引用传递对象;

     

     使用ARC生命周期限定符声明OC的对象变量时,语法如下:

         类名 * 限定符 变量名;

         如果没有设置限定符,系统会使用默认值__strong;

     

     应用于属性的ARC生命周期限定符:

     1)strong:

         等同于retain特性,获取对象所有权;

     

     2)weak:

         类似于assign特性,无数次被问到过assign和weak的区别,两者都是简单赋值操作,区别在于,weak特性限定的,如果引用对象被释放了,其实例变量会被设置为nil;

     

     ARC中,strong是对象型属性默认的所有权特性;

     (后续会详细介绍一下属性的特性)

     

     4.4.3 使用ARC

     

     ARC中类的init方法(无对象变量赋值)和MRR中的一样;

     但dealloc方法不同,ARC中的不调用父类的dealloc方法,因为这是由ARC自动执行的操作;

     

     给出一个例子:

     MRR:

     -initWithName:(NSString *)name{

         if(self = [super init]){

             _name = name;

             [_name retain];

         }

         return self;

     }

     -(void)dealloc{

         [_name release];

         [super dealloc];

     }

     

     ARC:

     -initWithName:(NSString *)name{

         if(self = [super init]){

             _name = name;

         }

         return self;

     }

     -(void)dealloc{

     

     }

     

     通过ARC内存管理方式创建的对象,不再使用时(比如置为nil,或作用范围结束),ARC会自动释放它们;

     ARC还会管理必需的依存对象,避免出现正在使用对象的情况;

     

     4.4.4 避免循环引用

     

     OC的引用计数模型是通过获取对象所有权(通过retain消息),以及再不使用对象后释放对象的所有权(通过release)实现的;

 

     ARC自动化了该过程;

         它会根据需要在代码中自动插入retain/release/autorelease消息;

     

     然而,如果两个对象直接或间接相互引用,就会导致循环引用问题;

         比如,类A的对象a拥有一个类B的实例,如果类B的这个实例对象也拥有类A的对象实例,就会在这两个对象之间造成循环引用;

         两个对象将永远不会被释放;

     

     解决方式是使用弱引用:

         弱引用是一种非所有权引用,被弱引用的对象不属于引用它的对象,从而消除循环引用;

     

     OC约定:

         父对象强引用其所有子对象;

         子对象弱引用其父对象;

     

     因此上述的问题可以这样修改:

     @Interface A:NSObject{

     @public B * b;

     }

     @Interface B:NSObject{

     @public A * __weak a;

     }

     

     当B类对象被释放时,变量a也会被置为nil;避免了循环引用;

     

     

     4.5 小结

     

     本章介绍了:

     OC中的内存管理,包括:

         OC内存模型;

         为OC程序分配和释放内存的方式;

         以及两种OC内存管理机制的用法;

     

     要点:

     1)在运行时,OC程序创建的对象(通过NSObject类的alloc方法)会以动态方式存储在预先分配的内存区域中,这片内存区域称为堆内存;

         以动态方式创建对象意味着需要管理内存,因为在堆内存中创建的对象会一直使用该区域中的内存;

         不进行内存管理或者采用错误的内存管理方式,通常会导致内存泄漏和悬挂指针问题;

     

     2)OC的内存管理是使用引用计数实现的;

         该技术通过对象的唯一引用判断对象是否正在被使用;

         如果某个对象的引用计数变为0,那么就会被认为不再有用;运行时系统会释放它占用的内存;

     

     3)OC开发环境有两种内存管理机制:手动管理(MRR)和自动引用计数(ARC);

     4)在使用MRR内存管理方式时,需要编写确切的代码,管理对象的生命周期、获取对象(你创建的或需要使用的)所有权和释放对象(不再需要的)所有权;

     

     5)ARC使用的引用计数模型与MRR使用的引用计数模型相同,不同的是ARC通过编译器自动管理对象的生命周期;

         在编译程序时,编译器会分析源代码,确定以动态方式创建的对象的生命周期,然后在已编译的代码中自动插入必需的retain和release消息;

     

     6)ARC中增加了新的对象生命周期限定符,使用这些限定符可以确切地声明对象变量和属性的生命周期,还可以实现弱引用,避免出现循环引用;

     

     精巧的OC程序仅会占用它所必需的内存,不会使内存泄漏和尝试访问已经失效的对象;

     

     接下来做好准备,迎接下一章——预处理器。



该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动!


上一节介绍了消息传递和消息转发,接下来我们看看内存管理相关的内容;





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值