C 指针和OC 对象之间的转换方法

2020-01-06 18:40:43丽君

__bridge_transfer <#Objective-C type#>)<#expression#>

__bridge_transfer 等同于 CFBridgingRelease() .

将非 OC 对象转换为 OC 对象,同时将对象的管理权交给 ARC,开发者无需手动管理内存.

示例:


CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
CFStringRef strUUID = CFUUIDCreateString(kCFAllocatorDefault, uuid);
NSString *str = (__bridge_transfer NSString *)strUUID;
//无需释放 strUUID
//CFRelease(strUUID);
CFRelease(uuid);

CFBridgingRelease 实现如下:


NS_INLINE id _Nullable CFBridgingRelease(CFTypeRef CF_CONSUMED _Nullable X) {
 return (__bridge_transfer id)X;
}

上面的示例可以改写为:


CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
CFStringRef strUUID = CFUUIDCreateString(kCFAllocatorDefault, uuid);
NSString *str = CFBridgingRelease(strUUID);
 
//无需释放 strUUID
//CFRelease(strUUID);
 
CFRelease(uuid);

__bridge

__bridge 不改变对象所有权, 需要我们自己来管理内存, 它也是我们经常使用的方法, 从某种程度上来说, 它是上面两个方法的简化版本.

__bridge 可以将 OC 对象 与 C 指针相互转换, 示例:


//CFString -> OC 对象
CFStringRef cfString = CFStringCreateWithCString(kCFAllocatorDefault, "very", kCFStringEncodingUTF8);
NSString *nsString = (__bridge NSString *)cfString;
NSLog(@"CFString -> NSString: %@", nsString);
CFRelease(cfString);

如果将 CFRelease(cfString) 注释掉, Xcode 的静态检测器会告诉你有内存泄露的情况, 如图:

C,指针,OC,对象

再来另外一个例子, 如下:


//OC 对象 -> CFString
NSString *nstr = @"itman";
CFStringRef cfStringRef = (__bridge CFStringRef)nstr;
NSLog(@"NSString -> CFString: %@", cfStringRef);
CFRelease(cfStringRef);

无论是使用 CFRelease(cfStringRef) , 还是注释掉, 静态检测器都不会报错. 说明这种情况下, 当前的内存管理已经被 OC 对象管理.

野指针

运行下面的示例:


void *p;
{
 NSObject *objc = [[NSObject alloc] init];
 p = (__bridge void*)objc;
}
NSLog(@"mark: %@", (__bridge NSObject*)p);

会直接 crash, 如图:

C,指针,OC,对象

当 objc 这个对象超出作用域范围,其内存就会被回收,接着在作用域范围外用 void *p 去访问 objc 的内存,就造成了野指针.