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. nagios 完全配置手册

    Linux下Nagios的安装与配置   一.Nagios简介 Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows.Linux和Unix的主机状态,交换机路由器等网络设置,打印机 ...

  2. (jQuery 插件)封装容器的表单为json对象

    下面代码可以把一个页面容器中的表单元素封装成一个json对象. (function($){ $.fn.serializeObject=function(){ var inputs=$(this).fi ...

  3. 固定滚动外层div的css

    background-color: #2a3138; position: fixed; bottom: 0; left: 0; width: 100%; height: 57px; overflow: ...

  4. echo、print、print_r、printf、sprintf、var_dump的区别比较

    一.echoecho() 实际上不是一个函数,是php语句,因此您无需对其使用括号.不过,如果您希望向 echo() 传递一个以上的参数,那么使用括号会发生解析错误.而且echo是返回void的,并不 ...

  5. 如何在版本控制工具中管理Sencha Architect的項目

    根據數次痛苦的經歷結合stack overflow上的解答,發現原來還是可以使用svn.git之類的版本控制工具管理Sencha Architect生成的項目的. 具體的要點如下,假定項目記作{PRO ...

  6. Net Core Docker

    Net Core Docker轻量级的web框架   .net core现在已经有了大的发展,虽然笔者现在已经从事python开发,但是一直在关注.net的发展,在逛博客园的时候,发现有大家都会提到N ...

  7. BZOJ 1725: [Usaco2006 Nov]Corn Fields牧场的安排

    Description Farmer John新买了一块长方形的牧场,这块牧场被划分成M列N行(1<=M<=12; 1<=N<=12),每一格都是一块正方形的土地.FJ打算在牧 ...

  8. Json字符串转换为java对象的各种实现方法【json_lib框架、Gson、org.json】

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://mengzhengbin520.blog.51cto.com/7590564/12 ...

  9. VCC,VDD,VEE,VSS,VPP 表示的意义

    转自VCC,VDD,VEE,VSS,VPP 表示的意义 VCC,VDD,VEE,VSS,VPP 表示的意义 版本一: 简单说来,可以这样理解: 一.解释 VCC:C=circuit 表示电路的意思, ...

  10. 【HDU 2853】Assignment (KM)

    Assignment Problem Description Last year a terrible earthquake attacked Sichuan province. About 300, ...