Objective-C 初阶 —— __bridge __bridge_retained __bridge_transfer
一、ARC & MRC
1、ARC
ARC 就是自动引用计数. 每当一块内存被一个强引用(指针)指着, 这块内存的引用计数自动 +1, 而每当一个强引用(指针)被销毁或置空后, 这块内存的引用计数会自动 -1.
当然, 无论是 ARC 还是 MRC, 只要这块内存的引用计数为 0, 那么这块内存就会被自动释放.
2、MRC
MRC 就是手动引用计数. 就是指针(引用)的指与不指都不会影响内存的引用计数. 只有当你每调一次 retain / CFRetain, 这块内存的引用计数才会 +1; 每调一次 release / CFRelease, 这块内存的引用计数才会 -1.
当然, 只有当这块内存的总引用计数 (ARC 侧 + MRC 侧) 为 0 时, 这块内存才会被释放.
二、__bridge & __bridge_retained & __bridge_transfer
1、__bridge
__bridge 只会基于 Core Foundation 的引用创建一个 Foundation 里的引用, 或基于 Foundation 引用创建一个 Core Foundation 的引用; 并不会自动帮你调 CFRetain 或 CFRelease.
但需要注意的是: 如果你在 Core Foundation 侧通过 __bridge 创建一个 Foundation 侧的引用, 由于这块内存被 Foundation 侧的引用指着, 而 Foundation 是遵循 ARC 的, 因此 ARC 侧会增加一个引用计数, 于是这块内存总的引用计数 (CoreFoundation/MRC 侧 + Foundation/ARC 侧) 就会 +1.
2、__bridge_retained
__bridge_retained 会基于 Foundation 的引用创建一个 Core Foundation 的引用, 然后自动帮你调一次 CFRetain() 函数.
因此 __bridge_retained 会自动为 MRC 侧增加一个引用计数, 导致这块内存的总引用计数 (CoreFoundation/MRC 侧 + Foundation/ARC 侧) +1.
3、__bridge_transfer
__bridge_transfer 会基于 CoreFoundation 侧的引用创建一个 Foundation 侧的引用, 然后再自动帮你调一次 CFRelease() 函数.
因此 __bridge_transfer 会自动为 CoreFoundation/MRC 侧减少一个引用计数; 同时因为 Foundation 侧遵循 ARC, 所以 ARC 侧又会增加一个引用计数, 因此这块内存总的引用计数 (CoreFoundation/MRC 侧 + Foundation/ARC 侧) 是没变的.
三、Demo 展示
如果大家想看更直观的对比, 可以在 command line tool 拷贝下面的代码, 看看引用计数的变化.
//
// main.m
// toll-free bridge
//
// Created by chuanzhima on 2025/10/26.
//#import <Foundation/Foundation.h>#define PRINT_RC(obj, name) NSLog(@"[RC] %@ (%p): %ld", name, obj, CFGetRetainCount((__bridge CFTypeRef)obj))void demo_bridge_retained(void) {NSLog(@"\n--- Demo 1: __bridge_retained ---");// 1️⃣ ARC 创建一个堆对象NSMutableString *str_arc = [[NSMutableString alloc] initWithString:@"Hello Retained"];PRINT_RC(str_arc, @"初始 str_arc");// 预期 RC = 1// 2️⃣ __bridge_retained:增加 RC,ARC 不再管理CFStringRef cfStr = (__bridge_retained CFStringRef)str_arc;PRINT_RC((__bridge id)cfStr, @"__bridge_retained 之后");// 3️⃣ ARC 侧清空引用str_arc = nil;NSLog(@"ARC 清空 str_arc");PRINT_RC((__bridge id)cfStr, @"str_arc 置 nil 后");// 4️⃣ CF 侧转换为 F 侧NSMutableString *str_arc1 = (__bridge NSMutableString *)cfStr;NSLog(@"CF 侧转换为 F 侧");PRINT_RC(str_arc1, @"CF 侧转换为 F 侧后");str_arc1 = nil;PRINT_RC((__bridge id)cfStr, @"str_arc1 置空后");// 5️⃣ 手动释放 CF 持有的引用CFRelease(cfStr);NSLog(@"手动 CFRelease 后,对象应释放\n");
}void demo_bridge_transfer(void) {NSLog(@"\n--- Demo 2: __bridge_transfer ---");// 1️⃣ CF 创建对象(手动管理)CFMutableStringRef cfStr = CFStringCreateMutableCopy(NULL, 0, CFSTR("Hello Transfer"));PRINT_RC((__bridge id)cfStr, @"初始 cfStr");// 2️⃣ __bridge_transfer:ARC 接管并 CFRelease 一次NSString *str_arc = (__bridge_transfer NSString *)cfStr;PRINT_RC(str_arc, @"__bridge_transfer 之后");// 3️⃣ 作用域结束,ARC 自动释放 str_arcNSLog(@"str_arc 即将离开作用域 (ARC 将自动释放)\n");
}void demo_bridge(void) {NSLog(@"\n--- Demo 3: __bridge ---");// 1️⃣ CF 创建对象(手动管理)CFMutableStringRef cfStr = CFStringCreateMutableCopy(NULL, 0, CFSTR("Hello Bridge"));PRINT_RC((__bridge id)cfStr, @"初始 cfStr");// 2️⃣ __bridge:仅类型转换,不改变所有权NSString *str_arc = (__bridge NSString *)cfStr;PRINT_RC(str_arc, @"__bridge 转换后");// 3️⃣ ARC 不会负责释放,需要手动 CFReleaseCFRelease(cfStr);NSLog(@"手动 CFRelease 完成 (ARC 不参与)\n");
}int main(int argc, const char *argv[]) {@autoreleasepool {demo_bridge_retained();demo_bridge_transfer();demo_bridge();}return 0;
}
