《iOS面试题整理》- 谈谈你对 ARC 的理解

ARC 定义

ARC (Automatic Reference Counting) 是指内存管理中采用自动引用计数, iOS 中 LLVM 编译器设置 ARC 为有效状态时, 就不需再手动插入 retain 和 release

什么是引用计数

引用计数是管理对象生命周期的一种方式, 创建对象的时候, 引用计数为1, 有一个新的指针指向这个对象的时候, 引用计数 +1, 当这个新指针不再指向这个对象的时候, 引用计数 -1, 当引用计数为 0 的时候, 可以将对象销毁, 回收内存

ARC 规则

  • 设置 ARC 有效

    • LLVM 编译器 版本 >= 3.0 (Xcode 4.2 之后的版本)
    • 指定编译器属性为 -fobjc-arc
  • 关闭 ARC

    • 指定编译器属性为 -fno-objc-arc
  • 所有权修饰符

    • __strong : id 类型和对象类型的默认所有权修饰符
      • 自己生成的对象, 自己持有
      • 非自己生成的对象, 自己也能持有
      • 不再需要自己持有的对象时释放
      • 非自己持有的对象无法释放
  • __weak:弱引用
  • __unsafe_unretained : 不属于编译器内存管理的对象
  • __autoreleasing :
    • 编译器会检查方法名是否以 alloc/ new / copy / mutableCopy 开始, 如果不是则自动将对象注册到 autoreleasepool
    • 对象作为函数的返回值, 编译器会自动将其注册到 autoreleasepool
    • 使用 __weak 修饰的变量, 就要使用注册到 autoreleasepool 中的对象, 确保对象存在
      id __weak obj1 =  obj0;
      id __autoreleasing tmp = obj1;
    
    • id 的指针或者对象的指针在没有显示指定时, 会被附加上 __autoreleasing 修饰符
    • 赋值给对象指针时, 所有权修饰符必须一致
    // 报错
    NSError *error = nil;
    NSError **pError = &error;
    
    // 正确
    NSError *error = nil;
    NSError * __strong  *error = &error;
    
    • 函数带有 __autorelease 参数的优化, 所有权不同但是不会由警告
    - (BOOL)executeError:(NSError * __autoreleasing *) error;
    
    NSError __strong * error = nil;
    [self executeError: &error];
                |  |
           自动转换成下面的调用
                |  |
      NSError __strong *error = nil;
      NSError __autoreleasing *tmp = error;
      [self executeError:&tmp];
    

⚠️ 所遵循的规则

  • 不能使用 retain / release / retainCount / autorelease
  • 不能使用 NSAllocateObject / NSDeallocateObject
  • 遵循内存管理方法命名规则
    • alloc / new / copy / mutableCopy 开头的方法必须返回调用方所持有的对象
    • ARC 有效的情况下 init 开头的方法也必须返回对象
  • 不显示调用 dealloc
  • 使用 @autoreleasepool 代替 NSAutoreleasePool
  • 不能使用 NSZone
  • 对象变量不能作为 C 语言的结构体成员
  • 显示转换 id 和 void *

__bridge 、__bridge_retain 、 __bridge_transfer

  • __bridge: CF 和 OC 对象转化时只涉及对象类型不涉及对象所有权的转化
  • __bridge_retain : OC 对象转换成 CF 对象时, 将 OC 对象所有权交给 CF 对象来管理
  • __bridge_transfer: CF 对象转成 OC 对象时, 将 CF 对象的所有权交给 OC , ARC 能自动管理内存

ARC 实现

__strong

  // 调用 alloc / new / copy / mutableCopy 方法
  id __strong obj = [NSObject alloc] init];
        |  |
        |  |
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_release(obj);

  // 调用其他方法
 id __strong obj = [NSMutableArray array];
        |  |
        |  |
id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);

__weak

  • 从 weak 表中获取废弃对象的地址为键值记录
  • 把 __weak 修饰符变量的地址全部置为 nil
  • 从 weak 表中删除记录
  • 从引用计数表中删除废弃对象的地址为键值得记录

alloc
底层调用了 calloc

dealloc

  • _objc_rootDealloc
  • rootDealloc
  • object_dispose
  • objc_destructInstance
  • clear_deallocating

你可能感兴趣的:(《iOS面试题整理》- 谈谈你对 ARC 的理解)