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];