美文网首页
Objective-C高级编程读书笔记

Objective-C高级编程读书笔记

作者: MaZengyi | 来源:发表于2017-01-08 22:06 被阅读28次

    自动引用计数

    ARC

    自动引用计数 ARC :是指内存管理中对引用计数采取自动计数的计数。

    苹果文档

    ARC 是让编译器来进行内存管理。设置了 ARC 为有效状态,就无需再次键入 retain 或者 release 代码。降低了程序崩溃,内存泄漏等风险的风险的同时,很大程度减少了开发程序的工作量。编译器完全清楚目标对象,并能立刻释放那些不再使用的对象。

    内存管理

    • 自己生成的对象,自己所持有
    • 非自己生成的对象,自己也可以持有
    • 不再需要自己持有的对象时释放
    • 非自己持有的对象无法释放
    • autorelease 对象
    对象操作 Objective-C 方法
    生成并持有对象 alloc/new/copy/mutableCopy等方法
    持有对象 retain
    释放对象 release
    废弃对象 dealloc

    自己生成的对象,自己所持有

    下列名称开头的方法名意味着自己生成的对象自己所持有。

    • alloc
    • new
    • copy
    • mutableCopy

    实例代码

    id obj = [NSObject new];
    

    非自己生成的对象,自己也可以持有

    用 alloc/new/copy/mutableCopy 以外的方法取得的对象,因为非自己生成并持有,所以不是该对象的持有者。但是我们可以持有它

    实例代码:

    // 取得非自己生成的对象
    id obj = [NSMutableArray array];
    
    // 持有非自己生成的对象
    [obj retain];
    

    不再需要自己持有的对象时释放

    自己持有的对象,一旦不在需要,持有者有义务释放该对象,释放使用 release。
    实例代码:

    // 自己生成并持有对象
    id obj = [[NSObject alloc] init];
    
    // 释放对象
    [obj release];
    

    同理,用 alloc 方法由自己生成并持有的对象通过 release 方法就释放了。非自己生成而持有的对象,若用 retain 方法变为自己持有,也可以使用 release 方法释放。

    // 取得非自己生成的对象
    id obj = [NSMutableArray array];
    
    // 持有对象
    [obj retain];
    
    // 释放对象
    [obj release];
    

    非自己持有的对象无法释放

    释放非自己持有的对象会造成崩溃
    实例代码:

    // 自己生成并持有
    id obj = [NSObject new];
    // 释放持有对象
    [obj release];
    // 释放非自己持有的对象,因为之前已经释放了。crash !!!
    [obj release];
    

    autorelease 对象

    autorelease 对象可以达到对象存在但是自己又不持有的效果。如 [NSMutableArray array]

    实现方案:

    - (NSMutableArray *) array
    {
          // 创建并持有对象
          id obj = [NSObject new];
          // 取得对象存在,但是自己不持有
         [obj autorelease];
         return obj;
    }
    

    autorelease 对象会被 autoreleasepool 所持有,在 runloop 休眠的时候会释放所持有的对象。

    GUNstep 的计数实现

    将引用计数存在对象占用的内存块头部的变量中。

    • 在 Objective-C 的对象中存在引用计数这一个整数值。
    • 调用 alloc 或是 retain 方法后,引用计数值加 1。
    • 调用 release 后,引用计数减 1。
    • 引用计数值为 0 时,调用 dealloc 方法废弃对象。

    苹果的实现

    苹果使用了散列表来管理引用计数。
    对比:

    GUNstep

    • 少量代码即可完成。
    • 能够统一管理引用计数用内存块与对象用内存快。

    Apple

    • 对象用内存快的分配无需考虑内存块头部。
    • 引用计数表各记录中存在内存块地址,可以从各个记录追溯到各对象内存块。利于调试。

    autorelease

    autorelease 对象可以达到对象存在但是自己又不持有的效果。autorelease 对象离开作用域都将调用 release 实例方法。
    具体使用(MRC):

    1. 生成并持有 NSAutoreleasePool 对象。
    2. 调用已分配对象的 autorelease 实例方法。
    3. 废弃 NSAutoreleasePool 对象。

    实例代码:

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    id obj = [NSObject new];
    [obj autorelease];
    [pool drain];
    

    ARC 规则

    所有权修饰符

    • __strong 修饰符
    • __weak 修饰符
    • __unsafe_unretained 修饰符
    • __autorelease 修饰符

    __strong 修饰符

    __strong 是默认修饰符
    __strong 修饰符表示对对象的强引用。持有强引用的变量在超出其作用域时被废弃,随着强引用失效,引用的对象会随之释放。

    • 如果是自己生成的对象正常持有。
    • 如果不是自己生成的对象,会自动加 retain 来持有。

    __weak 修饰符

    __strong 修饰符会造成循环引用问题,__weak 修饰符可以避免循环引用。__weak 不持有对象,在对象被释放的时候会自动设置为 nil。
    __weak 修饰符只能用于 iOS 5 以上以及 OS X Lion 以上版本,其他版本需要使用 __unsafe_unretained 来替代。

    __unsafe_unretained 修饰符

    __unsafe_unretained 修饰符是不安全的所有权修饰符。尽管 ARC 是由编译器管理的,但是 __unsafe_unretained 修饰符修饰的变量不属于编译器的内存管理对象。
    和 __weak 不持有对象一样。释放了不会被设置为 nil,会出现野指针的情况。

    __autorelease 修饰符

    在 ARC 下不能显示的调用 autorelease 方法,那么需要使用 __autorelease 修饰。
    实例代码:

    // MRC 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    id obj = [NSObject new];
    [obj autorelease];
    [pool drain];
    
    // ARC
    @autoreleasepool{
      id __autorelease obj = [[NSObject alloc] init];
    }
    

    知识点:

    1. 访问 weak 变量是必须访问注册到 autorelease 的对象,因为 weak 修饰符只持有对象的弱引用,而在访问过程中,该对象可能被废弃。如果把要访问的对象注册到 autoreleasepool 中,那么在 runloop 周期内都不会给释放。
    2. id 的指针和对象的指针(如 NSError **)没有显示的修饰符那么默认是 __autorelease.

    ARC 下编写代码规则

    • 不能使用 retain / release / retainCount /autorelease。
    • 不能使用 NSAllocateObject / NSDeallocateObject。
    • 必须遵守内存管理的方法命名规则。
    • 不要显式的调用 delloc。
    • 使用 @autoreleasepool 块来替代 NSAutoreleasePool。
    • 不能使用区域(NSZone)
    • 对象型变量不能作为 C 语言结构体的成员。
    • 显示转换 id 和 void *。

    Toll-Free Bridge

    Core Foundation 对象和 Objective-C 对象没有区别,不同之处只是由哪个框架生成对象, Core Foundation 对象可以转换成 Objective-C 对象来使用,转换过程称之为 Toll-Free Bridge。有以下几个关键字

    • __bridge :只做类型转换,但是不修改对象(内存)管理权
    • __bridge_retained:将Objective-C的对象转换为Core Foundation的对象,同时将对象(内存)的管理权交给我们,后续需要使用CFRelease或者相关方法来释放对象。
    • __bridge_transfer:将Core Foundation的对象转换为Objective-C的对象,同时将对象(内存)的管理权交给ARC。

    ARC 实现

    strong 修饰符

    编译器来管理,2 种情况

    1. alloc/new/copy/mutableCopy等方法生成的对象,会自动插入 release方法。
    2. 非情况 1 方法生成的对象,如 [NSMutableArray array] ,会分别插入objc_autoreleaseReturnValueobjc_retainAutoreleasedReturnValue方法。

    objc_autoreleaseReturnValueobjc_retainAutoreleasedReturnValue是成对出现的。在对象返回处调用objc_autoreleaseReturnValue,并且强引用的时候紧接着会调用objc_retainAutoreleasedReturnValue
    系统会对这个其中赋值过程进行优化。

    过程图解.png

    weak 修饰符

    weak 对象流程

    1. 初始化 weak:objc_initWeak
    2. 改变 weak 值:objc_storeWeak
    3. 释放 weak 值:objc_destroyWeak

    Blocks

    什么是 Blocks

    Blocks 是 C 语言的扩充功能:带有局部变量的匿名函数。
    其他语言中的 Blocks 的名称

    语言 名称
    C Blocks
    Smalltalk Blocks
    Ruby Blocks
    LISP Lambda
    Python Lambda
    C++ Lambda

    语法

    ^ 返回值类型 参数列表{
      表达式
    }
    

    Blocks 变量

    语法(用在属性,变量处)

    返回值类型 (^ 变量名)参数列表
    

    截获自动变量

    • 普通变量获取值得内容
    • 指针变量强引用指针对象

    __block

    截获的自动变量不能子啊 Blocks 块内被修改,需要加 __block 修饰符。

    Blocks 的实现

    一个 Blocks 被编译后会生成这么几个结构体

    • __block_impx:包含了 isa,标志位,保留字段,执行的函数指针。
    • __xxx_block_desc_x:包含了保留字段,block 的大小。
    • xxx_block_impx_xxx:包含了上面 2 个成员。

    x 表示由编译器决定的名字。

    截获自动变量的原理

    截获的变量,会在__block_impx 中生成相应的成员变量。普通变量值是拷贝值,指针则是强引用指针。

    __block 修饰符

    当用 __block 修饰符的时候,会多生成__Block_byref_val_x,包含了被捕获的值,isa,forwarding 指针等字段。
    之所以可以在 block 内部修改 __block 变量因为生成这个结构体来包装了一层,通过这个结构体达到修改外部变量的目的。

    forwarding 指针

    当一个栈 block 执行出了作用域的时候,其捕获的 __block 变量也会出作用域,会出现野指针,如果把 __block 拷贝到堆上,这个时候这个 __block 变量也应该一同拷贝,需要有一个机制在被拷贝之后也会引用到系统的堆变量上。forwarding 指针就是做这个的,forwarding 在未被拷贝的时候始终指向自己,在拷贝之后 forwarding 指针会指向堆变量。防止了野指针的问题,也解决了拷贝之后的引用问题。

    循环引用

    在使用 block 由于捕获变量都是强引用的,所以需要注意循环引用。可以使用 weak 变量来避免循环引用。

    更详细的内容可以看我另外一篇Block 博客

    未完待续...

    相关文章

      网友评论

          本文标题:Objective-C高级编程读书笔记

          本文链接:https://www.haomeiwen.com/subject/rfrcbttx.html