ARC __bridge modifiers demystified
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的更多相关文章
- 李洪强iOS经典面试题135-Objective-C
可能碰到的iOS笔试面试题(5)--Objective-C 面试笔试都是必考语法知识的.请认真复习和深入研究OC. Objective-C 方法和选择器有何不同?(Difference between ...
- runtime/KVO等面试题
整理中... 1.KVO内部实现原则 回答:1>KVO是基于runtime机制实现的 2>当某个类的对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中 ...
- iOS面试题04-runtime
runtime/KVO等面试题 1.KVO内部实现原则 回答:1>KVO是基于runtime机制实现的 2>当某个类的对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个 ...
- 面试题汇总--数据储存/应用程序/UI控件/客户端的安全性与框架处理。。。
一 数据储存 1.如果后期需要增加数据库中的字段怎么实现,如果不使用 CoreData 呢?编写 SQL 语句来操作原来表中的字段1)增加表字段ALTER TABLE 表名 ADD COLUMN 字 ...
- 获取图片的metaData
获取图片的metaData 获取简易的metaData较为容易,以下是测试图: 以下是本人提供的源码: UIImage+MetaData.h // // UIImage+MetaData.h // P ...
- 李洪强经典面试题49-Objective-C
李洪强经典面试题49-Objective-C 面试笔试都是必考语法知识的.请认真复习和深入研究OC. Objective-C 方法和选择器有何不同?(Difference between method ...
- IOS-4-面试题1:黑马程序猿IOS面试题大全
一.多线程网络 1. 多线程的底层实现? 1> 首先搞清楚什么是线程.什么是多线程 2> Mach是第一个以多线程方式处理任务的系统.因此多线程的底层实现机制是基于Mach的线程 3> ...
- 汇编指令详解--as手册
https://sourceware.org/binutils/docs/as/ Table of Contents 1 Overview 1.1 Structure of this Manual 1 ...
- iOS技术面试03:Foundation
是否可以把比较耗时的操作放在NSNotificationCenter中 如果在异步线程发的通知,那么可以执行比较耗时的操作: 如果在主线程发的通知,那么就不可以执行比较耗时的操作 3.Foundati ...
随机推荐
- 网站开发常用jQuery插件总结(八)标签编辑插件Tagit
一.Tagit插件功能 提高网站交互性,增加用户体验.至于其它的功能,还真没有.用一个input text就可以替换了它.但是text没有输入提示功能,而tagit拥有这个功能.官方示例如下图: 将关 ...
- php 加载函数 __autoload(), spl_autoload_register()
来自:http://www.cnblogs.com/myluke/archive/2011/06/25/2090119.html spl_autoload_register (PHP 5 >= ...
- [C#]Base使用小记
base 关键字用于从派生类中访问基类的成员: • 调用基类上已被其他方法重写的方法. • 指定创建派生类实例时应调用的基类构造函数. 基类访问只能在构造函数.实例方法或实例属性访问器中进行. 从静态 ...
- 下载APP 2个二维码合并到一个二维码
<html> <head> <meta http-equiv="Content-Type" content="text/html; char ...
- python之PIL安装问题
··在windows安装模块 总是出现问题,今天安装PIL的 首先提示我的是pip命令出错,这应该是当你安装Python2.7的时候 并没有把pip模块添加进去 导致出现了这样的一个问题,为了省事,我 ...
- workerman安装
1.workerman安装 workerman是php的一个socket框架,简化了socket编程,已经为很多企业所用,今天在centos的ngix+php下安装了workerman,过程记录如下. ...
- C# net部署图片分布式存储服务器的小案例
如果web服务用户多了,访问多了,用户上传的图片,文件等内容放在一块,想必服务器是承受不住的,这个时候,我们就需要考虑分布式存储的方法了. 如图所示:一个web服务器拖2个图片服务器 如何做到用户上传 ...
- SAP修改前台屏幕字段文本
首先,要找到需要修改文本所对应的数据元素: 其次,进入CMOD,点击菜单栏中“转到--文本增强--关键字--更改”,填入数据元素,进入下一屏幕.将显示的文本全部改为自己需要的文本,保存即可.
- hdu 4752
计算几何+数值计算的题目: 要用到辛普森积分,没有学过~~~ 参考学习了acm_Naruto大神 的代码! 代码: #include<cstdio> #include<cmath&g ...
- 禁止form表单回车键进行提交
使用EasyUI的时候,我们会给一个datagrid添加一个搜索栏,但是这个搜索栏的form,我们一般使用ajax向服务器提交数据,因此在这样一个环境下可以考虑禁止用户按回车键(Enter)提交.代码 ...