1
2
3
4
5
6
7
8
|
NSURL*fileURL=[[NSBundlemainBundle]URLForResource:filenamewithExtension:nil];
if(fileURL!=nil)
{
SystemSoundIDtheSoundID;
OSStatuserror=AudioServicesCreateSystemSoundID((CFURLRef)fileURL,&theSoundID);
if(error==kAudioServicesNoError)
soundID=theSoundID;
}
|
这里代码尝试把一个NSURL指针强制转换为一个CFURLRef指针。这里涉及到一些Core Services特别是Core Foundation(CF)的东西,AudioServicesCreateSystemSoundID()函数接受CFURLRef为参数,这是一个CF的概念,但是我们在较高的抽象层级上所建立的是NSURL对象。在Cocoa框架中,有很多顶层对象对底层的抽象,而在使用中我们往往可以不加区别地对这两种对象进行同样的对待,这类对象即为可以”自由桥接”的对象(toll-free bridged)。NSURL和CFURLRef就是一对好基友好例子,在这里其实CFURLRef和NSURL是可以进行替换的。
通常来说为了代码在底层级上的正确,在iOS开发中对基于C的API的调用所传入的参数一般都是CF对象,而Objective-C的API调用都是传入NSObject对象。因此在采用自由桥接来调用C API的时候就需要进行转换。但是在使用ARC编译的时候,因为内存管理的原因,编译器需要知道对这些桥接对象要实行什么样的操作。如果一个NSURL对象替代了CFURLRef,那么在作用区域外,应该由谁来决定内存释放和对象销毁呢?为了解决这个问题,引入了__bridge,__bridge_transfer和__bridge_retained三个关键字。关于选取哪个关键字做转换,需要由实际的代码行为来决定。如果对于自由桥接机制感兴趣,大家可以自己找找的相关内容,比如适用类型、内部机制和一个简介~
__bridge :内存管理的负责人没有改变
__bridge_transfer:转移对象释放权
__bridge_retained:这种转换将在转换时将retainCount加1。和CFBridgingRelease()相似,也有一个内联方法CFBridgingRetain()来负责和CFRelease()进行平衡。
需要记住的原则是,当在涉及CF层的东西时,如果函数名中有含有Create, Copy, 或者Retain之一,就表示返回的对象的retainCount+1了,对于这样的对象,最安全的做法是将其放在CFBridgingRelease()里,来平衡retain和release。
需要注意的是,并非所有的CF对象都是自由桥接的,比如Core Graphics中的所有对象都不是自由桥接的(如CGImage和UIImage,CGColor和UIColor)。另外也不是只有自由桥接对象才能用bridge来桥接,一个很好的特例是void (指向任意对象的指针,类似id),对于void 和任意对象的转换,一般使用_bridge。(这在将ARC运用在Cocos2D中很有用)