ARC __bridge modifiers demystified - objective-c

I was asked recently by one of my friends about the new bridge modifiers that became active under ARC. He asked me if I knew which ones to use in specific times and what the difference between the different __bridge modifiers were. He asked me,"so how do they work, when do I use them, how do I use them , and how do they work "under the hood" "?
Note: This was supposed to be a "Share your knowledge" type of question, where I answered the question myself, but I'm not sure I set it up properly.

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!

Related

Objective-C release for unnamed(temporary, non-lvalue) variables

I trying to learn Objective-C memory management, and was wondering if I can write my code to work properly in both ARC and Non-ARC cases. So ended up with following code, where did not name any variable:
CFStringRef fileref_to_localpath(CFStringRef fileRefURL)
{
// one liner to convert file URL(like file:///<path>) to machine specific path
return (__bridge CFStringRef)[[NSURL URLWithString:(__bridge NSString *)fileRefURL] path];
}
So, my question do I need to release something that I did not name in first place?
1) First of all: Core Foundation objects are not "auto-countable", so you have to write CFRelease and CFRetain whenever you work with CF type whether it's ARC or MRC.
__bridge is not transferring ownership to/from ARC, it just "casts" object to desired type. Having this in mind, you should think of your code in two different ways: ARC and MRC.
In ARC - you should call CFRelease on CF objects when you finished with them, only if originally this object was obtained with CF and You are responsible for it. The main rule of object responsibility is: If you created an object or got it with functions with "Create" or "Copy" - then you are responsible for it.
In MRC - you should retain when you are planning to use temporary object in future, and release it later when you are done with it and/or use autorelease.
2) Second point:
CFStringRef url = (CFStringRef)#"file:///home/gautam/index.cpp";
has excessive allocations, use CFSTR(const char *) instead like:
CFStringRef url = CFSTR("file:///home/gautam/index.cpp");
According to Apple docs
A value returned by CFSTR has the following semantics:
Values returned from CFSTR are not released by CFString—they are
guaranteed to be valid until the program terminates.
You can retain and release values returned from CFSTR in a balanced
fashion, like any other CFString, but you are not required to do so.
3) here:
return (__bridge CFStringRef)[[NSURL URLWithString:(__bridge NSString *)fileRefURL] path];
Even new NSURL object is created, you are not responsible to release it in MRC because URLWithString: and path don't start with “alloc”, “new”, “copy”, or “mutableCopy”. (thanks #Willeke) This mean that they are already in autorelease pool.
See Basic Memory Management Rules for help. (Also was useful for me)
Correct me if I am wrong.
P.S. If you want to transfer object from CF to NS or from NS to CF
for "forever", look at CFBridgingRelease and CFBridgingRetain
UPD: corrected post according to comments

When and when to not allocate memory to objects

NSArray *array = [dictionary objectForKey:#"field"];
and
NSArray *array = [[NSArray alloc] initWithArray:[dictionary objectForKey:#"field"]];
I see both kind of approaches very frequently in objective C code.
When tried to understand, I found both of them used in similar situation too, which makes contradiction. I am not clear on when I should use 1st approach and when 2nd one?
Any idea?
Detailed explanation and useful references are moms welcome.
First off, those two examples are doing slightly different things. One is retrieving something from an existing dictionary and one is creating a new array by retrieving something from an existing dictionary (the value of that key is an array).
But, if you're asking the difference between getting objects by alloc vs. convenience methods. ([NSString alloc] init vs [NSString stringWith ...), by convention, you own anything that you call alloc, new copy or mutableCopy on. Anything that you call that is not those, is autoreleased.
See the memory guide here. Specifically, look at the rules.
Getting an autoreleased object means it will go away at some point in the near future. If you don't need to hold onto outside the scope of that function, then you can call autorelease on it or use one of the convenience methods that's not alloc, etc...
For example:
// my object doesn't need that formatted string - create the autoreleased version of it.
- (NSString) description {
return [NSString stringWithFormat:#"%# : %d", _title, _id];
}
// my object stuffed it away in an iVar - I need the retained version of it. release in dealloc
- (void) prepare {
_myVal = [[NSString alloc] initWithFormat:"string I need for %d", _id];
}
In the first example, I created a convenience methods for others to call, my class doesn't need that object beyond the scope of that method so I create the autoreleased version of it and return it. If the caller needs it beyond the scope of his calling method, he can retain it. If not he can use it and let it go away. Very little code.
In the second example, I'm formatting a string and assigning it to an iVar variable that I need to hold onto for the lifetime of my class so I call alloc which will retain it. I own it and releasing it eventually. Now, I could have used the first version here and just called retain on it as well.
You have a fundamental misunderstanding of allocations versus instance methods.
The first example, NSDictionary's -objectForKey method, returns id, not an instance of NSDictionary, therefore it does not allocate or initialize the variable.
The second, however is the classic retain part of the retain-release cycle.
The two methods are fundamentally equal (if we are to assume that array is alloc'd but empty in the first, and nil in the second), and both get ownership of the array object. I would go with the second, as it guarantees a reference, and it's shorter.
What I think you're confusing this with are new and convenience methods. Convenience methods (like NSNumber's +numberWithInt:, NSString's +stringWithFormat:, and NSMutableArray's +array), return an autorelease instance of the class (usually). New takes the place of alloc and init in just one word.

How are #"Strings" allocated in memory?

I am curious of the memory allocation for the following code.
NSString *myString = [NSString string];
I know this will create an autoreleased empty string, #""
What happens when I then call
myString = #"Hello world";
Is my reference the same as the autoreleased object NSString provided or did I just allocate a new object that I am responsible for releasing?
When wondering whether you own an object, ask yourself:
Does the method I used to create this object...
begin with new?
begin with alloc?
contain copy?
equal retain?
If you can answer "Yes" to any of those, then you are responsible for invoking release or autorelease on the returned object. (Note that the rules for Core Foundation objects are slightly different. Also note that anything that the documentation explicitly says that contradicts this wins. The documentation always supersedes the guidelines)
In the case of your string, the answers to all your questions are "no", so you are not responsible for the object. Constant strings (of the style #"foo") are hard-coded into the application binary and cannot be deallocated. That, however, is an implementation detail. As long as you follow the memory management rules, you'll be good!

Does this Objective-C code leak memory?

One thing I'm concerned about is I create two ints, but don't release them. Would it be better to make them NSIntegers?
-(void) flipCoin {
int heads = [headsLabel.text intValue];
int tails = [tailsLabel.text intValue];
if (random() %2 ==1 )
{
heads++;
}
else {
tails++;
}
headsLabel.text = [NSString stringWithFormat:#"%d", heads] ;
tailsLabel.text = [NSString stringWithFormat:#"%d", tails];
}
As sha notes, local variables get allocated in the current stack frame. As soon as the current function call returns, the stack gets "popped", and the memory occupied for the current call is not released so much as abandoned, until it is overwritten by the next call that gets pushed into that part of the stack.
So why do we have to release variables like this:
MyClass *myObject = [[MyClass alloc] init];
Well, you actually don't have to worry about "myObject". It's on the stack, just like your ints, and it will get cleaned up when the current call finishes.
What you have to worry about is the memory that myObject—which is a pointer—points to. It's off somewhere on the heap. Constructing an object involves asking the runtime for some semi-permanent place to put it; that process returns a memory address, which your pointer stores.
alloc and release are Objective-C idioms that largely replace C's malloc() and free() functions, but all of them ultimately are asking the computer to set aside memory on the heap, and all of that memory must ultimately be returned, either through an autorelease pool, a release message, or a free() call.
int is what is known as a primitive type. It is not a pointer to an Objective-C object so you cannot release it. You can't even send a message to it.
NSInteger is also a primitive type in the sense that it is a typedef to a primitive type (long usually). So you can't release that either.
What do you need to release? You need to release any object you obtained by sending new, alloc or a method containing copy. You also need to release objects to which you have sent retain. So all of the local variables in the following must be released:
-(void) foo
{
NSString* aString = [[NSString alloc] init];
NSString* aString2 = [aString copy];
NSString* aString3 = [someOtherString retain];
NSString* aString4 = [#"some string" copy];
}
NB due to implementation details, you would actually get away with not releasing the aString4 but you don't need to worry about it.
No. Your heads and tails variables are local and stored on the stack. This won't cause a leak. Your two NSString assignments near the bottom are created using convenience constructors and will be autoreleased for you.
All default datatypes (int, char, BOOL, etc) are automatically managed for you, and do not (and cannot) be released (for all intents and purposes).
NSIntegers behave likewise, as they are just signed ints (or signed longs on 64-bit machines).
Objects you initialize, however, like NSString or NSArray will usually have to be released (unless they are autoreleased, like the NSStrings at the bottom of your code). If you ever call -alloc and -init on something, you will have to later release it. If you ever doubt whether a method returns an autoreleased object, just read the documentation (it will tell you).
Also, if you want to read up on memory management, there are plenty of wonderful sources that will teach you (Google is a great place to start!), and if you ever think that your code leaks memory, run it through Instruments, and you'll be able to tell...

Memory cleanup on returned array from static method (objective-c)

In objective-c, I have a utility class with a bunch of static methods that I call for various tasks. As an example, I have one method that returns an NSArray that I allocate in the static method. If I set the NSArray to autorelease, then some time later, the NSArray in my calling method (that is assigned to the returned pointer) losses it's reference because the original form the static method is cleaned up. I can't release the NSArray object in the static method because it needs to be around for the return and assignment.
What is the right way to return an object (like the NSArray) from a static class, and have it hang around for the calling class, but then get cleaned up later when it is no longer needed?
Do I have to create the object first in the caller and pass in a pointer to the object and then return that same object form the static method?
I know this is a basic O-O problem, I just never had this issue in Java and I do not do much C/C++.
Thanks for your help.
Your autorelease is correct in the return just retain it when you call the static method.
NSArray *data = [[StaticClass getArray] retain];
If you have a property for the place your assigning the return value to, you can just do self.data = .. and the retain is automatic.
Please take the time to read over the rules. These apply to all of the frameworks you'll be using, and should apply to your code as well. Burn these into your head, and they'll become second nature. Thankfully, it's not complex, rather simple.
It's quite simple. If you do not own an object, it will go away at some indeterminate point in the future. In your case, the "indeterminate" point is when the autorelease pool gets drained, which in the normal case, is at the end of processing the current event.
If you want an object to hang around, you need to own it. The memory management rules referred to by jer will tell you exactly how you get ownership of an object. In this case, you need to retain the object. You must then, of course, release it later when you have done with it.
Regards your comment to Matt's answer. Your code is this:
for (NSString * date in dateList)
{
[historyList addObject:[[BIUtility historyForDate:date] retain]];
}
and
+ (NSArray *) historyForDate:(NSString *)date
{
NSMutableArray * ret = [[[NSMutableArray alloc] init] autorelease];
}
The first thing you need to know is that collections retain their members, so, in fact, your retain of the historyForDate is unnecessary. You don't want to own that object, historyList does. If it's disappearing, it's probably because historyList itself is being deallocated (because you don't own it) or is nil.
By the way, historyForDate: does nothing with the date. Is that correct?