iOS中的__bridge,__bridge_transfer和__bridge_retained

OC对象与CF对象的桥接

一、Core Foundation框架与Foundation框架类型之间的桥接

Core Foundation框架是C语言接口,而Foundation使用OC语言,在同时使用时,数据类型会有差异,我们可能需要OC与CF之间进行相互转化,这时我们就需要__bridge系列声明。

1、OC转CF,__bridge、__bridge_retained声明

假设一个类型转化的场景,例如:

NSURL *url = [[NSURL alloc] initWithString:@"http://www.xxx.com"];
CFURLRef ref = (CFURLRef)url;

此时,编译器会报错,如下图:
这里写图片描述
提示OC指针类型转化C指针类型要求使用桥接,
我们可以看到有两种fix的方式,
第一种提示使用__bridge做直接类型转换,不会改变所有权。

//点击第一个fix,自动补充为:
CFURLRef ref = (__bridge CFURLRef)url;

第二种提示使用CFBridgingRetain,将一个ARC对象作为count+1的CF对象(CF对象不是ARC对象,所以需要我们手动管理内存,retain/release,这里相当于retain)。

//点击第二个fix,自动补充为:
CFURLRef ref = (CFURLRef)CFBridgingRetain(url);
//我们也可以手写成
CFURLRef ref = (__bridge_retained CFURLRef)url;

在此处我们进到CFBridgingRetain方法里,可以看到方法本身等同于__bridge_retained,
所以,两种写法都是可以的。
同时我们还可以看到注释说明:

// After using a CFBridgingRetain on an NSObject, the caller must take responsibility for calling CFRelease at an appropriate time.
NS_INLINE CF_RETURNS_RETAINED CFTypeRef _Nullable CFBridgingRetain(id _Nullable X) {
    return (__bridge_retained CFTypeRef)X;
}

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

说明,当使用__bridge_retained之后,你就有责任去使用CFRelease释放内存,去做内存管理。

NSURL *url = [[NSURL alloc] initWithString:@"http://www.xxx.com"];
CFURLRef ref = (__bridge_retained CFURLRef)url;
CFRelease(ref);  //释放内存

2、CF转OC类型,__bridge、__bridge_transfer声明

那么我们反过来,需要将一个CF类型转成OC类型,例如:

CFAllocatorRef allocator;
CFStringRef URLString;
CFURLRef baseURL;
CFURLRef ref = CFURLCreateWithString(allocator,URLString,baseURL);
NSURL *url =(NSURL *)ref;

同样,此时编译器会报错,如下图:
这里写图片描述
显示我们需要进行桥接,
同样第一种fix是直接转换类型,不涉及所有权。
而第二种是将拥有的CF对象,转化为OC-ARC对象,由ARC处理内存,自己不用在关心内存处理。

//第一种fix
NSURL *url =(__bridge NSURL *)ref;
//第二种fix
NSURL *url =(NSURL *)CFBridgingRelease(ref);
//同样可以手写成
NSURL *url =(__bridge_transfer NSURL *)ref;

猜你喜欢

转载自blog.csdn.net/zramals/article/details/79226391