Do methods retain arguments in Objective-C? - iphone

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.

Related

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

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.

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.

Autoreleasing object returned from NSMutableArray

When a method returns an object that is taken from and NSMutableArray does the object must be autoreleased? Check the following method. Also should I autorelease the nil value?
-(NSObject*)getElementByID:(NSString*)ID{
for(int i=0;i<[elements count];i++){
NSObject *element = (NSObject*) [elements objectAtIndex:i];
if([element.key isEqualToString:ID]){
return [element autorelease];
}
}
return nil;
}
You must not autorelease element because you are not an owner of it (you have not put a retain on it). You would have become an owner of it if you acquired it using alloc, new or retain. Since you acquired this object calling objectAtIndex:, you do not own it. See Three Magic Words. Calling autorelease here will cause a crash later do to over-release.
Your method name is incorrect and breaks KVC. A method that begins with get must take a pointer that will be updated with the result. This should be elementForID:. As noted above with the three magic words, naming in ObjC is very important to writing stable code
As a side note, it is traditional to use id is most cases rather than NSObject*. They mean slightly different things, but typically id is correct.
You never need to do any memory management related things to nil. So, no, you should not send autorelease to nil.
You also should not need to send autorelease to the element object that you are returning from your elements array. That object you are returning will remain in memory by virtue of elements itself having retained it. If the calling method would like to retain the value that you return, it may. But if that calling method only uses the returned value within its own scope, it is safe for it to do so without retaining it.

What happens after I release a deallocated object?

I created
object *Obj = [[Obj alloc] init];
Obj retain count is 1. After I release it, the object is deallocated.
If I try to release the object again, what will happen?
EXT_BAD_ACCESS most likely since your object reference is no longer valid.
The code may crash. But it may just as well work most of the time.
You brake a rule, you may get caught. But you may just as well get away with it, living in constant fear that you may get caught later on.
There’s an important distinction to be made here: you can’t release the object again, because the object no longer exists. If you send another message to the variable (be it release or any other message), the behaviour is undefined because the variable is no longer known to point to a valid object. (It’s possible that the address the variable now points to will have been reused for a different object, in which case it may not crash, but of course that’s still a bug.)
Once the retain count of an object reaches 0, it is released, and all further attempts to access it will result in random behaviour.
If you use autorelease instead, the retain count will not be lowered, and the object will be put in the autoreleasepool. The object will only lower its retain count once it reaches the autoreleasepool drain command, which is usually done on a much higher level in a much broader scope. If you really need the object after the autoreleasepool is drained, you should retain it before drain is executed, or else it will have exactly the same behaviour as in my first paragraph.
Get EXT_BAD_ACCESS. Because of you are already release it and now try to release again.
your object reference is no longer valid.

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.