在 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 接收者会触发 “最快路径优化” 。
- 被调用方:
return [[NSObject alloc] init];(编译器视情况插入objc_autoreleaseReturnValue)。 - 调用方:
__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 的影响 | 赋值时 ,断开/作用域结束时 |
| 底层函数 | objc_storeStrong, objc_release |
| 默认性 | 所有未声明修饰符的局部变量和属性默认为 __strong |
| 风险点 | 容易导致循环引用(必须配合 __weak 或 __unsafe_unretained) |