2-6.【OC】【内存管理】ARC 下,__strong 的真实含义是什么?

2 阅读3分钟

在 ARC 环境下,__strong 是 Objective-C 指针的默认修饰符。它的真实含义可以从所有权语义生命周期管理以及底层运行时实现三个维度来解剖。

简单来说,__strong 的本质是:只要指针还指向这个对象,对象就必须活着;一旦指针不再指向它,所有权立即释放。


1. 语义:持有(Ownership)与维持(Persistence)

当你声明 __strong id obj = ... 时,你实际上是在与编译器达成一项契约:

  • 获得所有权:无论对象是通过 alloc 创建的,还是从一个方法返回的,只要赋值给 __strong 指针,该对象的引用计数(RC)就会确保至少为 1。
  • 自动延命:只要这个 obj 变量还在作用域内,且没有被重新赋值,它所指向的对象就绝对不会被销毁。

2. 行为:底层函数的精准插入

编译器为了实现 __strong 的语义,会在赋值和作用域结束时插入特定的底层函数。

A. 赋值操作:objc_storeStrong

当你写 obj = anotherObj; 时,编译器会将其转化为:

C++

// 伪代码实现
objc_storeStrong(&obj, anotherObj) {
    id temp = obj;
    if (temp == anotherObj) return;
    objc_retain(anotherObj); // 持有新值
    obj = anotherObj;
    objc_release(temp);      // 释放旧值
}

这就是为什么 __strong 属性能够自动处理“先释放旧值,再持有新值”的逻辑,完全避免了 MRC 下常见的野指针问题。

B. 作用域结束:objc_release

在 MRC 时代,你必须时刻记得在函数末尾写 [obj release]。而在 ARC 下,编译器会追踪 __strong 变量的生命周期,在它离开作用域(即大括号 } 处)的前一刻,精准地插入 objc_release(obj)


3. 内存模型:引用计数的“强锁”

__strong 是引用计数模型的物理体现。

  • 它会实实在在地增加 isa 指针中的 extra_rc 位。
  • 物理对比__weak 只是在侧表(SideTable)里记下你的地址,不改计数;而 __strong 是直接修改对象的引用计数值。

4. 关键特例:方法的返回值

这是 __strong 最聪明的地方。如果一个方法返回一个对象(通常是 autorelease 的),__strong 接收者会触发 “最快路径优化”

  1. 被调用方:return [[NSObject alloc] init];(编译器视情况插入 objc_autoreleaseReturnValue)。
  2. 调用方:__strong id obj = [self getObject];(编译器插入 objc_retainAutoreleasedReturnValue)。

真实含义:在这种情况下,__strong 不仅仅是简单的 retain,它会尝试跳过全局的 AutoreleasePool 栈操作,直接从被调用者手中接管对象,这被称为 “所有权移交优化”


5. 局限性:无法感知“逻辑回路”

__strong 唯一的盲点在于它只管“局部所有权”,不管“全局拓扑”。

  • 如果 A __strong 指向 B,B 也 __strong 指向 A,双方都在等待对方释放。
  • 即便 A 和 B 的局部变量都离开了作用域,由于它们内部互相持有的 __strong 关系,它们的引用计数永远不会回到 0。

这就是**循环引用(Retain Cycle)**的根源。__strong 就像一根坚固的铁链,它保证了连接的牢固,但也可能把自己锁死。


总结

__strong 的真实含义是:它是 ARC 内存管理的“定海神针”。它将繁琐的“内存地址操作”抽象成了“对象生命周期管理”。

维度__strong 的表现
对 RC 的影响赋值时 +1+1,断开/作用域结束时 1-1
底层函数objc_storeStrong, objc_release
默认性所有未声明修饰符的局部变量和属性默认为 __strong
风险点容易导致循环引用(必须配合 __weak__unsafe_unretained