博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ARC __bridge modifiers demystified
阅读量:6705 次
发布时间:2019-06-25

本文共 8710 字,大约阅读时间需要 29 分钟。

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:

enter image description here

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!

转载地址:http://bdflo.baihongyu.com/

你可能感兴趣的文章
C#中的数据格式转换 (未完待更新)
查看>>
基于 Python 官方 GitHub 构建 Python 文档
查看>>
ArcSDE:C#创建SDE要素数据集
查看>>
arulesSequences包做序列模式的关联分析
查看>>
下面以Button组件为例,开始FLEX皮肤制作的入门。
查看>>
CSS学习(一)
查看>>
SQL Server 数据库安全
查看>>
Android双机(网络和USB)调试及其完美ROOT
查看>>
Linux Suspend过程【转】
查看>>
算法-大整数加法
查看>>
变量命名那点小事
查看>>
程序员敏捷之路秘笈:降龙十八掌
查看>>
Java 基础【02】 Super 用法
查看>>
makefile初步制作,arm-linux- (gcc/ld/objcopy/objdump)详解【转】
查看>>
VS2005中建立解决方案及多项目
查看>>
C语言ASM汇编内嵌语法【转】
查看>>
关于内核中spinlock的一些个人理解 【转】
查看>>
我的测试自动化框架原则设计手册(时刻更新)
查看>>
C#里巧用DateTime预设一些可选的日期范围(如本年度、本季度、本月等)
查看>>
固定高度div,随内容自动变高css定义方法
查看>>