Can somebody tell me what retain and release exactly do in objective-c? - iphone

I have a bit of confusion about retain and release variable.
These are my question:
I have an object A allocated
Object *A = [[Object alloc] init]
Does this increase the retain count? Is it the same as having
Object *A = [[[Object alloc] init] retain].
I know if we call retain, the object will be held until we released it.
2.1.
I have a retained Object A. This Object A was passed to a function as an argument. Later in the function I released it. Will it release the memory of the Object A? if it is, does the Object A no longer existed.
2.2
Follow on with 2.1, instead of releasing Object A. I created a local variable Object *B = A. If I released Object B will it also release Object A. Or if I retain B, will it retain A as well.
I am a bit of confused so I want to ask anyone here to directing me to the right path.
Thanks

Object *A = [[Object alloc] init] Does this increase the retain count?
Yes, more specifically, likely, it initializes the retain count to 1.
Is it the same as having Object *A = [[[Object alloc] init] retain]. I know if we call retain, the object will be held until we released it.
Not the same. That will increase the retain count twice. There's not much reason to increase the retain count twice in the same place. If you did do that, you'd be responsible for calling release twice.
I have a retained object A. This Object A was passed to a function as an argument. Later in the function I released it. Will it release the memory of the Object A? if it is, does the object A no longer existed.
First, you should make sure that you understand that whether release frees memory or not depends on if there are other owners that are holding a reference to the object. If more than one thing has retained the object, then release will not free the memory in that case.
Second, bad idea. To keep sanity with reference counting, you should follow certain patterns.
retain (or alloc) instance variables, release them in dealloc or before.
retain (or alloc) local variables if needed, and release them before you exit the method.
The caller does not own the return value of a function. That implies that you handle a function return value like a local variable, but autorelease it before you return it instead of releasing it. That ensures it will last at least long enough for the caller to retain it, if needed.
One of the patterns is not for a method caller to own a reference to a method argument, but when the function returns the caller does not own the reference. The method should not release the caller's reference.
Follow on with 2.1, instead of releasing Object A. I created a local variable Object *B = ObjectA. If I released B will it also release Object A. Or if I retain B, will it retain A as well.
retain and release are sent to objects, not references. A and B refer to the same object, so it's the same calling retain or release on one as on the other.
It is legitimate, but probably unnecessary, to [B retain] and later in the same method [B release]. But do not do [B release] only, thereby expropriating A's ownership of the object.

Remember this: NARC.
New, Alloc, Retain, Copy are the 4 commands that will increase the retain count. In other words, for every NARC, you need a corresponding release to release that memory.

Calling alloc (or new) increases the retain count. If you retain again after that, that increases it once again. There is no need to do that second retain except for specific wanted cases.
The main rule is : the one that alloc is the one that release. Of course you can bypass that if you reaaly know what you are doing.
I have a retained object A. This Object A was passed to a function as
an argument. Later in the function I released it. Will it release the
memory of the Object A?
Basically, Yes.
if it is, does the object A no longer existed.
Yes again, but sometimes, it remains "in memory" so calls to it may work for a very very short time. Very short.
Follow on with 2.1, instead of releasing Object A. I created a local
variable Object *B = ObjectA. If I released B will it also release
Object A. Or if I retain B, will it retain A as well.
if you retain B, then the object references by A is retained twice. so releasing B does not free the object referenced by A. But if you don't retain B, then releasing B equals to releasing A (only one retain count).
Tip
Imagine that any reference you declare (Balloon* rope) is a rope you get in your hand to retain a Balloon object that contain things. The rope is not the object. The object (the balloon) is created somewhere in memory (here in the space). If you retain a second time, you get another rope to that balloon and get it in the other hand. To free the balloon, you need to free both ropes.
Note that alloc (or new) creates a rope so the balloon you've just created does not go immediatly in outerspace.
Is that clear ?

1) init is not the same as retain.
The init method actually puts the object in a correct "initialization" state so that the object can be used by calling the parent classes init method, as well as setting up any additional setup that is placed in the init method implemented in the objects .m file. The retain actually just increments the retain count by 1.
2) 2.1) When you allocate memory for an object, you want to release it in the same scope per say, so when you pass in an object into a method you wouldn't release it there. However, if you did release it in the function/method where it was passed in since you are passing in an object reference, it will be released. You can't be entirely sure when the object itself will cease to exist though.
2.2) When you say Object *B = ObjectA you aren't actually creating another object, but are creating a new reference or pointer to ObjectA. If you call release/retain on the reference B, since it's pointing to the same object as ObjectA, it's the same thing as calling release/retain on ObjectA.

Related

Do methods retain arguments in Objective-C?

Do methods retain the arguments that are passed? If so, can I release these arguments in the next line? And if not, then when do I release these objects (in case I am allocating these locally)?
The language will not retain arguments automatically. However, code that obeys the rules will retain or copy anything that it needs to keep around after execution leaves its scope.
In other words:
id object = [[SomeClass alloc] init];
[otherObject doSomethingWithObject:object];
[object release];
This code should always be OK, because if doSomethingWithObject: needs to keep its argument around, it will send it retain, and if it doesn't, it won't.
No, they simply handle the object, they don't control the memory.
You should release something in the method it was created.
Or, if it's a property or an ivar, you should release it in the dealloc (if it is retained).
Methods do not increment the reference count. However if you assign it to a variable with retain count then you need to explicitly send a nil message to both. Release of a variable can be done when you no longer want to use it. So a allocated variable will have its reference count incremented whenever a retain message is sent to it. So you need to send equal number of release messages till reference count becomes zero.

What happens if you try to release an object that has been released?

What if I have an object, say NSIndexPath in which before I do a copy I always release it first?
Is it possible to have a memory count under 0?
I am doing this to prevent memory leaks.. is this a good way?
//global already has some value before in here or it doesn't have a value.. I want to update
//this with a new value (I no longer care to the old pointer)
[global release]
global = [indexPath copy];
Don't. When the retain count reaches 0, your object will be dealloc'ed and its pointer will become invalid, so using it again will cause unpredictable results (namely crashing).
You should read through Apple's Memory Management Guide.
This is the fundamental rule:
You only release or autorelease objects you own. You take ownership of an object if you create it using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message.
You use release or autorelease to relinquish ownership of an object. autorelease just means “send a release message in the future” (specifically: when the used autorelease pool receives a drain message).
Update:
As Josh pointed out, the one case you need to consider is when global and indexPath are the same. In that case, you would still "need" the pointer (to perform the copy), so you either autorelease (instead of releasing) or you use a temporary variable to handle that.
What you are doing is essentially correct, so long as global either has an old value that you no longer need or is nil. If it is one of a class's ivars, it will be nil when an instance of the class is created. The one catch is that if the new indexPath happens to be the same object as the one that's already in global, you will have over-released and you will crash.
// global points to object at 0x8BADFOOD
// indexPath also happens to be 0x8BADFOOD; for some reason, it
// hasn't changed since last time. This _can_ happen.
[global release]; // object at 0x8BADFOOD is deallocated
global = [indexPath copy]; // indexPath no longer valid!
// Crash! Bang! Boom!
The way to avoid this is to use a temp variable.
When you declare a property as copy and synthesize that property, the setter method that is created looks essentially like this, and you can do the same thing:
- (void)setMyFloozit:(Floozit *)newFloozit {
// Copy first in case newFloozit and myFloozit are for
// some reason the same object
// Take ownership of a copy of newFloozit
Floozit * tmp = [newFloozit copy];
// We no longer need old value of myFloozit, so we release it.
[myFloozit release];
// tmp contains a value that we own, we just need to assign
// it to the correct name.
myFloozit = tmp;
}
This could be made slightly better by checking first to see whether newFloozit and myFloozit are the same, and doing nothing if they are.

My block is not retaining some of its objects

From the Blocks documentation:
In a reference-counted environment, by
default when you reference an
Objective-C object within a block, it
is retained. This is true even if you
simply reference an instance variable
of the object.
I am trying to implement a completion handler pattern, where a block is given to an object before the work is performed and the block is executed by the receiver after the work is performed. Since I am being a good memory citizen, the block should own the objects it references in the completion handler and then they will be released when the block goes out of scope. I know enough to know that I must copy the block to move it to the heap since the block will survive the stack scope in which it was declared.
However, one of my objects is getting deallocated unexpectedly. After some playing around, it appears that certain objects are not retained when the block is copied to the heap, while other objects are. I am not sure what I am doing wrong. Here's the smallest test case I can produce:
typedef void (^ActionBlock)(UIView*);
In the scope of some method:
NSObject *o = [[[NSObject alloc] init] autorelease];
mailViewController = [[[MFMailComposeViewController alloc] init] autorelease];
NSLog(#"o's retain count is %d",[o retainCount]);
NSLog(#"mailViewController's retain count is %d",[mailViewController retainCount]);
ActionBlock myBlock = ^(UIView *view) {
[mailViewController setCcRecipients:[NSArray arrayWithObjects:#"test#recipient.com",nil]];
[o class];
};
NSLog(#"mailViewController's retain count after the block is %d",[mailViewController retainCount]);
NSLog(#"o's retain count after the block is %d",[o retainCount]);
Block_copy(myBlock);
NSLog(#"o's retain count after the copy is %d",[o retainCount]);
NSLog(#"mailViewController's retain count after the copy is %d",[mailViewController retainCount]);
I expect both objects to be retained by the block at some point, and I certainly expect their retain counts to be identical. Instead, I get this output:
o's retain count is 1
mailViewController's retain count is 1
mailViewController's retain count after the block is 1
o's retain count after the block is 1
o's retain count after the copy is 2
mailViewController's retain count after the copy is 1
o (subclass of NSObject) is getting retained properly and will not go out of scope. However mailViewController is not retained and will be deallocated before the block is run, causing a crash.
Do not use -retainCount.
The absolute retain count of an object is meaningless.
You should call release exactly same number of times that you caused the object to be retained. No less (unless you like leaks) and, certainly, no more (unless you like crashes).
See the Memory Management Guidelines for full details.
(cribbed from one of #bbum's answers)
As for your question:
Are you actually observing a crash? Or are you just shooting blindly from the hip and thinking that it might crash?
From the code you posted, it would appear that mailViewController is an instance variable, in which case the block would be retaining self instead of the instance variable. And since you autoreleased your instance variable, it's getting cleaned up by an NSAutoreleasePool just like you'd expect.
So in summary:
Do not use -retainCount.
Do not autorelease instance variables that you want to exist beyond this turn of the run loop.
edit A bit more clarification:
Here's what's going to happen when your block is created:
Inspect object references in its scope. There are two: self->mailViewController and o.
self->mailViewController is a member of a struct (self), so it is not retained directly. Retain self instead.
o is a local variable. Retain it.
This is proper behavior. As for your code...
o is created with a +0 retain count
self->mailViewController is created with a +0 retain count
myBlock is created with a +0 retain count. o now has a +1 RC, as does self. self->mailViewController still has a +0 RC
myBlock is copied => +1 retain count
Fast forward to the end of this run loop cycle.
The current autorelease pool is drained. All objects with a +0 retain count are deallocated, including self->mailViewController. self->mailViewController now points to deallocated memory, and is essentially garbage.
Fast forward to some future point when myBlock is executed
myBlock attempts to invoke a method on self->mailViewController. However, self->mailViewController no longer points to a valid object, and your app crashes.
However, if mailViewController is not an instance variable, then we need to see more code. I think it'd be highly unlikely that the behavior you're seeing is a problem with the blocks runtime, but it is possible.
The documentation no longer says that. It now correctly says:
In a manually reference-counted environment, local variables used
within the block are retained when the block is copied.
As the "mailViewController" is a member of your current class instance, so the block actually retain "self" here.

iphone - will the retain property propagate on an array?

I have a mutable array that has been retained.
This array contain dictionaries with lots of keys. Each dictionary contains objects.
Do I have to retain the dictionaries before adding them to the mutable array or will the array itself retain everything that is added to it (because it is already retained), including the sub objects of its objects in the hierarchy?
thanks.
A Foundation container, like NSArray or NSDictionary, retains the objects it directly owns, but not subobjects owned by the objects.
For example, if NSArray*a contains NSArray*b and it in turn contains NSArray*c, a retains b and b retains c but a doesn't retain c.
That said, your are thinking from a wrong perspective. It's not correct for you to wonder such as "do I have to retain this object (say x) before passing x to another object y, because y might not retain it appropriately?" The point of retain/release is that to make sure an object retains and releases objects it owns. You trust other objects to do the same.
Then, all you have to make sure if you put an object x to an array y, is for you not to release x (if it's not autoreleased) once it becomes unnecessary to you. If y needs it, y retains it, so you don't have to care about it.
Say you have a pre-existing NSMutableArray*array. Then you would do in a method something like this:
NSMutableDictionary* dictionary=[[NSMutableDictionary alloc] init];
... do something with dictionary ...
[array addObject:dictionary];
[dictionary release];
You see, it's the array's responsibility to retain the dictionary, if that array needs it. It needs it, and so it retains it. You don't have to care about that.
The method's responsibility is to retain the dictionary if the method needs it, to release it if the method no longer needs it. So, as shown above, the method releases it once it's done with it by adding it to the array.
Again: the whole point of retain/release is to allow you to consider the life cycle of an object very locally in the code.
Whenever you call a method method:of another object a by passing an object b, you don't have to worry as you do now whether method: retains b or not, and you don't have to worry if you need to retain b before passing b to method:.
It is because every method in the Cocoa framework, and every method you write, retain the object b passed to it if the method needs it later, and don't retain b if it doesn't need it later.
Objective-C containers (such as NSMutableArray) will retain the objects added to them.
This does not, however, have anything to do with anything being "propagated" -- whether or not you call -retain on the NSMutableArray is irrelevant. The NSMutableArray will simply retain objects added to it, and if those objects are themselves some kind of container (such as a dictionary), the sub-objects will themselves already have retained anything added to them, and so forth.
ps. there isn't really a "retain property", there's an (internal) "retain count" on each object. For example, if you create an NSString and add it to 3 NSMutableArray's, each of those arrays will retain it.

Do I need to explicitly alloc my NSNumber?

I am defining a number, as follows:
NSNumber *nn0 = [NSNumber numberWithInt:0];
It works fine without any alloc. My understanding is that if I use numberWithInt, alloc and init are called automatically.
If I try to release at the end of my function, I run into problems:
[nn0 release];
I get a runtime error.
My question is: if I use numberWithInt to initialise the NSNumber, do I have to do any memory management on it?
The "convenience constructors" for a lot of types produce an object that is automatically "autoreleased" - i.e. the new object will be retained by the current NSAutoreleasePool. You don't need to manually release these objects - they will be released when the current NSAutoreleasePool is released/drained.
See this page for a description of convenience constructors, and how to mange the memory for these.
http://www.macdevcenter.com/pub/a/mac/2001/07/27/cocoa.html?page=3
Just follow the core memory-management rule: If you "own" the variable, you have to eventually relinquish ownership. You take ownership by: creating the object (alloc/new/copy) or specifically taking ownership (retain). In all these cases, you're required to release it.
If you need the object to stick around, you need to take ownership of it. So if you know you only need the number for this method (like to pass it into an array or whatever), use the convenience method and just leave it at that. If you want to keep the number for some reason (and instance variable, for example), then you can safely alloc/init it.
If you release something that you don't own, you will get a runtime error.
The rule is simple, with very few exceptions:
If the selector returning an object has the word "new", "alloc", "retain" or "copy" in it, then you own the returned object and are responsible for releasing it when you are finished.
Otherwise you do not own it and should not release it. If you want to keep a reference to a non-owned object, you should call -[NSObject retain] on that instance. You now "own" that instance an must therefore call -[NSObject release] on the instance when you are done with it. Thus you do not own the instance returned by -[NSNumber numberWithInt:] and should not call -release on it when you are done. If you want to keep the returned instance beyond the current scope (really beyond the lifetime of the current NSAutoreleasePool instance), you should -retain it.
In RegEx terms, Peter Hosey lays it out very nicely in his blog. You own the returned object instance if the method selector matches this regex:
/^retain$|^(alloc|new)|[cC]opy/
Of course, the definitive reference is the Memory Management Programming Guide for Cocoa.