http://stackoverflow.com/questions/14207960/arc-bridge-modifiers-demystified

Because I learned what they were and how they operated just recently, I want to share with anyone else who wishes to learn about the __bridge modifiers under ARC which can be a source of confusion due to the fact that toll-free bridging used to be accomplished with a simple cast.

It used to be that if you wanted to, say, cast your NSArray object to a CFArrayRef for any purpose, it could be done with a simple cast like so:

     NSArray* myArray = [NSArray alloc]initWithObjects:....]; //insert objects

     CFArrayRef arrayRef = (CFArrayRef) myArray;

In this case, maybe you had an NSArray of colors and needed to cast it to CFArrayRef for using it with CoreGraphics to draw a gradient.

However with ARC, this will no longer work for you and you will receive this error:

Well what the heck does this mean!?!

Well it turns out, ARC doesn't like it when you do this kind of cast and will even give you a few "Fix it" solutions, which all seem to have that same __bridge keyword in them, so let's get right to them!

Under ARC we have 3 main __bridge modifiers:

__bridge

__bridge_retained ( which is partnered by the CFBridgingRetain function)

__bridge_transfer (which is partnered by the CFBridgingRelease function)

So we'll begin with __bridge. What is it? __bridge is just another way of saying: "Hey compiler, just give me my darn casted object!". The compiler will be happy to do so and return to you a casted object of your liking!

However, because you wanted a "freely" casted object like that, YOU are still responsible of releasing the memory for the originally allocated object. In this case, if I were to do this:

    NSArray* myArray = [NSArray alloc]init];
CFArrayRef arrayRef = (__bridge CFArrayRef) myArray;

I am still responsible for releasing the myArray memory because it was the originally allocated object. Remember, __bridge just tells the compiler to perform the cast!! And because I am compiling under ARC, I don't explicitly have to call [-release] on the myArray object, ARC will do it for me!

Note, that the __bridge modifier works both ways! (Hence, toll-free bridging) and you can just as easily cast a CF object to an NS object the same way ( that is toll-free bridgeable!) like so:

CFArrayRef arrayRef; // allocate this arrayRef and give it a value later on
//... amazing code.....
NSArray* myArray = (__bridge NSArray*)arrayRef;

But since the CF object would be the originally allocated object, I must call CFRelease(whatever);

Now let's move on to __bridge_retained and its partner in crime CFBridgingRetain() . This __bridge modifier is geared EXPLICITLY towards transferring the ownership of an NS object TO A CF OBJECT (So we'll be expecting to manually CFRelease(whatever) this due to it being a CF type object)

Meaning, if I were to do my old scenario again, but this time with __bridge_retained:

 NSArray* myArray = [NSArray alloc]initWithObjects:....]; //insert objects

 CFArrayRef arrayRef = (__bridge_retained) myArray;

the arrayRef object now has explicit ownership of the memory that used to be owned by the myArray pointer. Because now the CF type has ownership, I must release it myself using CFRelease(whatever);

So what role does the CFBridgingRetain() function play in all this chaos? It plays the same exact role as doing the cast we just talked about! Let's take a look at the function prototype for CFBridgingRetain:

    CFTypeRef CFBridgingRetain(id x);

We can see, it pretty much just simplifies the whole (__bridge_retained) notion into one function! We're gettting back a CF object after "inputting" an NS type object! Radical! Yes, I know this is awesome! Too much coolness to take in one sitting! And yes, it also performs the memory "ownership" transfer.. how awesome!

And last, but by no means least, __bridge_transfer and the almighty CFBridgingRelease() !

__bridge_transfer works almost like the opposite of __bridge_retained. The __bridge_transfer modifier transfers the ownership of a CF object type to an NS object type.

So let's refer to the example that's been used throughout this to dissect it:

 NSArray* myArray = [NSArray alloc]initWithObjects:....]; //insert objects

 CFArrayRef arrayRef = (__bridge_retained) myArray;

 // at this point, arrayRef holds the ownership
// Let's add this new line to change things up a bit: NSArray* otherArray = (__bridge_transfer NSArray*)arrayRef;

So what does this awesome little program that we just wrote exactly do?

Step 1: We allocated an NSArray

Step 2: We passed the ownsership of the array to the arrayRef object

// Before we continue to step 3, let's understand at this point arrayRef is the owner

Step 3: We re-transfer the ownership that USED to be owned by arrayRef back to an NSArray*

Because at this point, the otherArray pointer is the owner, it would seem sort of natural at this point to say [otherArray release] when we're done, right? Well this is where ARC kicks in and will take care of releasing that array for you!

And did you know it gets cooler? This __bridge modifier's awesome partner in crime: CFBridgingRelease()

makes it that much cooler! CFBridgingRelease has this function prototype:

   id CFBridgingRelease(CFTypeRef x);

And we see, this is exactly the same thing that happens when we cast with __bridge_transfer. And this function also transfers the ownership to the NS object! This is just fantastic!

Using the CFBridgingXXX functions maybe can make a little more sense at first, due to the fact that many objective-c programmers still have the notion of the NARC rule:

Everything that has been called with:

N ew

A lloc

R etain

C opy

must have a balancing -release call

So doing this:

     NSArray* myArray = [[NSArray alloc]init];
// there's the A of NARC!
//(cleaned by ARC)
CFArrayRef arrayRef = CFBridgingRetain(myArray); // there's the R of NARC!!
//NSArray* other = CFBridgingRelease(arrayRef); // cleaned up by ARC

Can make the process of learning the __bridge casts easier due to the fact that the retain was matched with a release

If all this still may be confusing, think of it this way: You are a pointer to any NS object type. For the sake of consistency, let's say you're an NSArray pointer, that right now isn't pointing to anything. So you can sort of imagine that you, as the nil pointer, are standing in a bathroom with the lights turned off. ( The lights turned off represents that you aren't pointing to anything).

Then, later on in code, your programmer decides to assign you to a new NSArray. i.e, he/she says this:

      you = [[NSArray alloc]init];

Suddenly, the lights in the bathroom you were standing in, have turned on! You're pointing to an object! Now in normal program execution, when you're done using the object, you release it. So in this case, when you're done using the bathroom, you turn the lights off.

But the program you're in, unfortunately, isn't very "normal". The programmer decided to use some CoreFoundation objects! Bleh!

And he writes this line of code:

    CFArrayRef other = (__bridge_retained CFArrayRef) you;

So now what happens is that, another person walks into the bathroom at the same time you leave. Out of politeness, you don't turn the lights off because there's another person using the restroom and is responsible for turning the lights off when he/she leaves

In this case, because the new owner of the restroom is a CF object, the programmer must manually release it.

But what if he/she were to write this:

   CFArrayRef ref = (__bridge CFArrayRef) you;

what happens here is that, another person just barged into the same restroom as you without even asking! How rude! On top of that he expects you to clean up after him too! So you, being a gentlemen/lady turn off the lights when both of you finish.

However, since you are an NS type object, ARC comes and cleans it for you :)

And finally, what if the programmer writes this:

    you = (__bridge_transfer NSArray*)arrayRef;

What happens here is the exact opposite of the first scenario. Instead of you leaving the restroom at the same time as someone enters, you're the one who enters while the other person leaves

The same memory management rules apply. Since you took over "owning" the restroom, you must manually turn off the lights. And because you're an NS type object, ARC will do it for you... again :) Isn't ARC such a beauty!

I know this may seem a bit intimidating and confusing at first, but just work your way through it, read it again and you'll find out how incredible this ARC mechanism works!

Thanks everyone for reading! Hope this helped :)

Thanks to @rob mayoff and @ Krishnabhadra for all the extra help and suggestions!

ARC __bridge modifiers demystified的更多相关文章

  1. 李洪强iOS经典面试题135-Objective-C

    可能碰到的iOS笔试面试题(5)--Objective-C 面试笔试都是必考语法知识的.请认真复习和深入研究OC. Objective-C 方法和选择器有何不同?(Difference between ...

  2. runtime/KVO等面试题

    整理中... 1.KVO内部实现原则 回答:1>KVO是基于runtime机制实现的 2>当某个类的对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中 ...

  3. iOS面试题04-runtime

    runtime/KVO等面试题 1.KVO内部实现原则 回答:1>KVO是基于runtime机制实现的 2>当某个类的对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个 ...

  4. 面试题汇总--数据储存/应用程序/UI控件/客户端的安全性与框架处理。。。

    一 数据储存  1.如果后期需要增加数据库中的字段怎么实现,如果不使用 CoreData 呢?编写 SQL 语句来操作原来表中的字段1)增加表字段ALTER TABLE 表名 ADD COLUMN 字 ...

  5. 获取图片的metaData

    获取图片的metaData 获取简易的metaData较为容易,以下是测试图: 以下是本人提供的源码: UIImage+MetaData.h // // UIImage+MetaData.h // P ...

  6. 李洪强经典面试题49-Objective-C

    李洪强经典面试题49-Objective-C 面试笔试都是必考语法知识的.请认真复习和深入研究OC. Objective-C 方法和选择器有何不同?(Difference between method ...

  7. IOS-4-面试题1:黑马程序猿IOS面试题大全

    一.多线程网络 1. 多线程的底层实现? 1> 首先搞清楚什么是线程.什么是多线程 2> Mach是第一个以多线程方式处理任务的系统.因此多线程的底层实现机制是基于Mach的线程 3> ...

  8. 汇编指令详解--as手册

    https://sourceware.org/binutils/docs/as/ Table of Contents 1 Overview 1.1 Structure of this Manual 1 ...

  9. iOS技术面试03:Foundation

    是否可以把比较耗时的操作放在NSNotificationCenter中 如果在异步线程发的通知,那么可以执行比较耗时的操作: 如果在主线程发的通知,那么就不可以执行比较耗时的操作 3.Foundati ...

随机推荐

  1. cp 命令参数

    cp命令         该命令的功能是将给出的文件或目录拷贝到另一文件或目录中,同MSDOS下的copy命令一样,功能十分强大.         语法: cp [选项] 源文件或目录 目标文件或目录 ...

  2. 查找PHP的配置文件

    查找PHP的配置文件 先写了一个 <?php phpinfo();?>然后在浏览器中浏览一下(之前我百度说在Configuration File  这个位置看) 结果竟然显示 Loaded ...

  3. 01_安装redhat 7.1时常出现的问题

    1. 笔记本安装时出现"dev/boot does not find ",进不去安装界面. 这是因为pci设备的问题,解决方法:在出现安装选项时,按Tab进入option模式,在末 ...

  4. c# 实现文件批量压缩

    今天改一个网站的功能,网站提供一些微信的素材,每个页面对应一套素材,如果会员一张一张下载,那么网站交互性就有点太差了.所以修改的内容就是提供一个按钮,点击按钮将这套图片和网站信息进行打包下载. 思路: ...

  5. [DevExpress]DxValidationProvider分享

    前些日子从研究所临时调回公司,帮忙做另外一个项目的控件验证工作,其实内容非常的简单,就是将用户即将提交至服务器的数据先做一个本地验证,以达到减少服务器压力.提高用户体验的目的. 附上一张图片 这是官方 ...

  6. Android自定义图片加载框架

    大神原网址: http://blog.csdn.net/lmj623565791/article/details/41874561  思路: 1. 压缩图片 压缩本地图片: 获得imageview想要 ...

  7. python 函数1

    一.背景 在学习函数之前,一直遵循:面向过程编程,即:根据业务逻辑从上到下实现功能,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,也就是将之前实现的代码块复制到现需功能处,如下 ...

  8. CCTV评论员评论步行者与奇才的比赛

    步行者客场迎战主场作战的奇才,奇才的战士可能由于过度兴奋或是过度紧张身体僵硬,本来能打进的球都失掉了.反而,由于步行者取得了两位数的领先,越大心情越放松,打出了过去很少见的流畅局面. CCTV评论员就 ...

  9. Windows 8 系统完全上手指南 - 非常详尽的 Win8 系统入门学习手册与使用技巧专题教程!

    每次当有新版本的操作系统发布的时候,市面上总会冒出各种从入门到精通类的学习书籍,这次最新的 Windows 8 也不例外!不过,今天给大家送上免费的大礼——<Windows 8 完全上手指南&g ...

  10. POJ 1837 Balance 01背包

    题目: http://poj.org/problem?id=1837 感觉dp的题目都很难做,这道题如果不看题解不知道憋到毕业能不能做出来,转化成了01背包问题,很神奇.. #include < ...