前言
前几天,《Objective-C高级编程》自动引用计数 阅读笔记 一文基本已经涉及到内存管理的各方面知识点,但是,在阅读《精通Objective-C》 第4章 内存管理的过程中,仍然可以学到不少东西,不仅仅是作者对于内存管理的另外一种理解方式,也从侧面反映出内存管理中不可或缺的重要的某些特性和要点。
Demo
Pro_Objective-C_ARC_Demo 提取码: i4p5
第4章 内存管理
问题1 对象引用和对象所有权
- 通过指向Objective-C对象内存地址的变量(即*** 指针*** ),以*** 间接方式*** 访问Objective-C对象。在声明时,指针的名称中会带有*前缀。
- 指针和间接访问方式可以应用于*** 所有Objective-C数据类型*** ,其中包括Objective-C的基本数据类型和C语言数据类型;然而,*** 对象指针*** 专门用于*** Objective-C对象的交互操作*** 。
- 对象指针实现了Objective-C对象的访问功能,但是它们本身*** 不能管理所有权*** 。(因此,才需要内存管理机制)
问题2 内存管理基本原则(思考方式)
- 自己生成的对象,自己持有(alloc/new/copy/mutableCopy方法群)
- 非自己生成的对象,自己也能持有(使用retain方法)
- 不再需要自己持有的对象时释放(可以使用release方法和autorelease方法)
- 非自己持有的对象不能释放(会导致潜在的悬挂指针问题)
*** 内存管理思考方式的讲解可以参考《Objective-C高级编程》自动引用计数相关章节。***
问题3 使用自动引用计数(ARC)
- ARC使用的引用计数模型与MRR使用的相同,但是由*** 编译器*** 管理回收对象(对象的生命周期)的工作。
- ARC可以(潜在地)提升应用的性能和消除内存管理错误(如错误释放正在使用的对象,保留不再使用的对象)。
- 与垃圾回收技术相比,ARC更可靠(保留和释放语句是在编译时插入的),并且不会为实现垃圾回收机制而在程序执行过程中引入暂停操作。
- ARC可以Objective-C对象和块提供*** 自动内存管理*** 。
- 由于ARC无法自动处理循环引用,Objective-C提供了*** 弱引用*** 功能,用于手动解除*** 循环引用*** 。
问题4 使用ARC的规则和约定
- 不能手动编写发送*** retain、retainCount、release、autorelease和dealloc消息*** 的代码,但是,如果需要管理实例变量之外的资源,可以手动编写dealloc方法。
- 不能直接进行*** id和(void *)类型的互转*** 。ARC只能管理Objective-C对象和块,因此编译器只能够处理Objective-C对象和块,而(void *)类型的指针是能够转换为任何指针类型(包括Objective-C中没有的指针类型)的通用指针,所以必须做此限制。
- 在autoreleasepool块结束时,*** 自动释放由ARC管理的对象***
- 不能调用Foundation框架中的*** NSAllocateObject函数*** 和*** NSDeallocateObject函数*** (因为这两个函数提供在指定内存区域中为对象分配和释放内存的功能,而Objective-C不再支持内存区,所以无法使用它们)。
- 不能使用*** C结构中的对象指针*** 。
- 不能使用*** 内存区(NSZone)*** 。
- 为了与非ARC代码协作,不能创建*** 以copy开头的方法*** 和*** 自动声明属性*** 。
- 默认情况下,ARC并非异常安全的:它无法释放异常失效的__strong变量,也无法在完整表达式抛出异常时,将位于该完整表达式末尾的对象释放。使用编译器选项*** -fobjc-arc-exceptions*** 可以启动处理ARC代码异常的功能。除非编译器解决了该异常,否则当弱引用异常失效是,ARC肯定会释放弱引用变量。
问题5 ARC的生命周期限定符(所有权修饰符)
*** 应用于常规变量的限定符 ***
- __strong: *** 默认的限定符设置*** 。表明变量持有alloc/new/copy/mutableCopy方法群创建的对象的强引用,变量会在其作用域里被保留)。
- __weak: *** 用于消除循环引用*** 。表明变量持有该对象的弱引用(即变量不持有该对象),对象随时可以被释放。当对象被释放后,附有__weak限定符的变量会被设置为nil。
- __unsafe_unretained: 与__weak限定符类似。但是,在对象被释放后,指针(即变量)不会被设置为nil,而是会处于*** 悬挂状态*** (不再指向合法对象)。
- __autoreleasing:*** 用于通过引用传递对象*** 。 alloc/new/copy/mutableCopy方法群以外的方法创建的对象,经编译器检查,会自动将返回值的对象注册到autoreleasepool中。
*** 应用于属性的限定符***
- strong: 等同于retain特性。
- weak: 类似于assign特性,但是如果引用对象被释放了,其实例变量会被设置为nil。
本章要点
介绍了Objective-C中的内存管理,其中包括Objective-C内存模型、为Objective-C程序分配和释放内存的方式,以及两种Objective-C内存管理机制的用法,要点有:
- 在运行时,Objective-C程序创建的对象会以动态方式存储在预先分配的内存区域中,这片内存区域称为*** 堆内存 *** 。以动态方式创建对象意味着*** 需要管理内存*** ,因为在堆内存中创建的对象会一直使用该区域中的内存。不进行内存管理或者采用错误的内存管理方式,通常会导致*** 内存泄露*** 和*** 悬挂指针*** 问题。
- Objective-C的内存管理是使用*** 引用计数*** 实现的,该技术通过对象的唯一引用判断对象是否正在被使用。如果某个对象的引用计数为0,那么就会被视为不再有用,运行时系统会释放它占用的内存。
- 苹果公司的Objective-C开发环境提供两种内存管理机制:*** 手动管理(MRR)*** 和*** 自动引用计数(ARC)*** 。
- 在使用MRR内存管理方式时,需要编写确切的代码,*** 管理对象的生命周期、获取对象(自己创建的或者需要持有的)所有权和释放对象(不再需要的)所有权*** 。
- ARC使用的引用计数模型与MRR使用的引用计数模型相同,但是它通过*** 编译器*** 自动管理对象的生命周期。在编译程序时,编译器会分析源代码,确切以动态方式创建的对象生命周期,然后在已编译代码中自动插入必需的*** retain*** 和*** release*** 消息。
- ARC中增加了新的对象生命周期限定符(也称所有权修饰符),使用这些限定符可以确切地声明对象变量和属性的生命周期,还可以实现弱引用功能(__weak修饰符),避免出现循环引用。
- ARC能够以工程为单位应用,也能以文件为单位应用,因此ARC代码可以与非ARC代码共存。
第6章 专家级技巧:使用ARC
问题1 Objective-C直接桥接数据类型
Core Foundation数据类型 | Foundation框架数据类型 |
---|---|
CFArrayRef | NSArray |
CFDataRef | NSData |
CFDateRef | NSDate |
CFDictionaryRef | NSDictionary |
CFSetRef | NSSet |
CFStringRef | NSString |
CFMutableArrayRef | NSMutableArray |
CFMutableDataRef | NSMutableData |
CFMutableDictionaryRef | NSMutableDictionary |
CFMutableSetRef | NSMutableSet |
CFMutableStringRef | NSMutableString |
CFNumberRef | NSNumber |
CFReadStreamRef | NSInputStream |
CFWriteSteamRef | NSOutputStream |
问题2 ARC桥接转换
*** __bridge标记 ***
使用__bridge标记可以在*** 不改变所有权*** 的情况下,将对象从Core Foundation框架数据类型转换为Foundation框架数据类型(反之亦然)。注意,该标记无法解决*** 内存泄露*** 和*** 悬挂指针*** 问题。
*** __bridge_retained标记 ***
使用__bridge_retained标记可以将Core Foundation框架数据类型对象转换为Foundation框架数据类型对象,并从ARC接管对象的所有权。*** 手动管理*** 直接桥接数据的生命周期。
*** __bridge_transfer标记 ***
使用__bridge_transfer标记可以将Foundation框架数据类型对象转换为Core Foundation框架数据类型对象,并且会将对象的所有权交给ARC管理。这样,由*** ARC管理*** 对象的生命周期。
注意:
转换标记位于数据类型之前。ARC桥接转换不仅可以用于直接桥接数据类型,还可以用于*** 访问未分配给Objective-C对象的内存*** 。
本章要点
深入研究了ARC的内存管理方式,着重介绍了ARC中的对象所有权、块对象和直接桥接(Toll free bridging),要点有:
- ARC*** 禁止*** 通过手动方式,向对象发送*** release、autorelease、dealloc消息以及与对象有关的其他消息*** 。
当执行下列操作时,程序会放弃对象的所有权:
- *** 重新分配变量(变量执行另外一个对象)***
- *** 将nil赋值给变量***
- *** 释放对象的拥有者***
- 当变量被更改为指向*** 另外一个对象*** 时,变量*** 原来的对象*** 会失去一个拥有者;在编译时,ARC会插入向该对象发送一条*** release消息*** 的代码。
- 当指向对象的变量被设置为*** nil*** 时,该对象会失去一个拥有者;在编译时,ARC会插入向该对象发送一条*** release消息*** 的代码。
- 当集合类实例被设置为nil时,集合类实例会被*** 释放*** ,ARC会自动向该集合类实例中的*** 每一个对象*** 发送一条*** release消息*** 。
- 苹果所提供的基于C语言的API软件库没有与ARC整合,因此,在程序中以动态方式为这些API分配内存时,必须*** 手动管理内存*** (用到了*** __bridge_retained转换符*** )。
- ARC禁止在Objective-C对象指针和其他类型指针之间标准转换,但是,通过多种机制(直接桥接和ARC桥接转换),可以使用在Objective-C程序中使用基于C语言的API。
- 在使用ARC时,无法直接转换直接桥接的数据类型,必须使用特殊的ARC桥接转换标记(*** __bridge、__bridge_retained、__bridge_transfer*** )才能进行转换。
网友评论