OC笔记-CFBridgingRetain和CFBridgingRelease

CFBridgingRetain和CFBridgingRelease

在Core Foundation框架和Foundation框架中有大量的可互换使用的数据类型。
这意味着你可以使用相同的数据类型,作为Core Foundation框架方法调用或Objective-C消息的参数或接收者。
这种在Core Foundation框架和Foundation框架之间交换使用数据类型的技术就叫"免费桥" (Toll-Free Bridging)。

一般我们使用CFBridgingRetain完成对NSObject对象转为CF实例,使用CFBridgingRelease完成CF实例转NSObject对象

CFBridgingRelease会导致CF实例引用计数-1,例如下面例子

void RunLoopSourcePerformRoutine (void *info)
{
    NSLog(@"RunLoopSourcePerformRoutine %p",info);
    RunLoopSource*  obj = (RunLoopSource*)CFBridgingRelease(info);
    NSLog(@"RunLoopSourcePerformRoutine %@",[obj valueForKey:@"retainCount"]);
    [obj sourceFired];
    obj = nil;
}

RunLoopSource* obj = (RunLoopSource*)CFBridgingRelease(info);
RunLoopSource* obj = (__bridge RunLoopSource*)(info);

在Runloop的自定义添加Source0回调中,返回的info可直接转换为RunLoopSource,但如果使用CFBridgingRelease,相当于把引用计数-1,会导致对象提前释放。所以在使用这个函数的同时,需要判断来源来自哪里,不要盲目就CFBridgingRelease

#if __has_feature(objc_arc)

// 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;
}

#else

// This function is intended for use while converting to ARC mode only.
NS_INLINE CF_RETURNS_RETAINED CFTypeRef _Nullable CFBridgingRetain(id _Nullable X) {
    return X ? CFRetain((CFTypeRef)X) : NULL;
}

// This function is intended for use while converting to ARC mode only.
NS_INLINE id _Nullable CFBridgingRelease(CFTypeRef CF_CONSUMED _Nullable X) {
    return [(id)CFMakeCollectable(X) autorelease];
}

#endif

显示转换id和void*

对于__bridge_transfer__bridge_retained,用于显示转换id和Void*
在ARC无效时,以下代码将id变量强制转换为void*变量并不会出问题

	/* ARC无效 */
	id obj = [[NSObject alloc] init];
	void *p = obj;

更进一步,将void*变量赋值给id变量中,调用其实例方法,运行时也不会有问题

	/* ARC无效 */
	id o = p;
	[o release];

但是在ARC有效时,会出现如下错误
Implicit conversion of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast
如果只想单纯的转换,不涉及变量持有关系,可以这样

	id obj = [[NSObject alloc] init];
	void *p = (__bridge void*)obj;
	id o = (__bridge id)p;

这样void*和id类型就能够互相转换。

_bridge转换中还有两种转换,__bridge_transfer__bridge_retained
__bridge_retained转换可使要转换赋值的变量也持有所赋值的对象

	id obj = [[NSObject alloc] init];
	void *p = (__bridge_retained void*)obj;

上面这段代码相当于ARC无效时的

	id obj = [[NSObject alloc] init];
    void *p = obj;
    [(id)p retain];

__bridge_transfer提供与此相反的动作,被转换的变量所持有的对象在该变量被赋值给转换目标变量后随之释放

	//p为void*类型
	id obj = (__bridge_transfer id)p;

ARC无效时,表述如下

 	/* ARC无效 */
    id obj = (id)p;
    [obj retain];
    [(id)p release];
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章