Do removeAllObjects and release of an NSMutableArray both have the same functionality? - objective-c

I have written the following line of code:
NSMutableArray *array=[[NSMutableArray alloc]init];
This allocates some memory. My question is, how can we later release this memory, whether using removeAllObjects method or [array release]?
Do both methods have the same functionality?

When you add an object to the array, the object's retain count will increase by 1. When you remove that object from the array, retain count will decrease by 1 to balance it out. But if you release the array, all objects will automatically receive a release message. So you don't need to call removeAllObjects before releasing the array.
Technically, these two method are not same. If you call removeAllObjects, the array will become empty and all objects will receive a release message but the array itself is still not released. The array will be released when you call release on it.

Related

The use of autorelease?

I am not clear about how to use autorelease;
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
RetainTracker* tracker = [RetainTracker new];
[tracker retain];
[tracker retain];
[tracker autorelease];
[pool release];
Is there any memory leak in the above code?
I know the autorelease just puts tracker into NSAutoreleasePool, without modifying the reference count for tracker. When i call [pool release], the object receives one message release, then the reference count of tracker is 2. So the compiler can't call the dealloc function of object tracker, so there is a memory leak.
So i get this: we shoul call retain and release same times, is it right?
If you're new to Objective-c, you should be using Automatic Reference Counting. Almost everyone should. But for the sake of understanding:
An object has a reference count of how many objects have a reference to it. When it drops to zero, the object is not referenced by anything and is deallocated. Every method in Objective-C is responsible for releasing any object it retains. The problem is, if a factory method's job is to create an object, it's breaking the rules by not releasing an object it retained (in this example it was retained because it was created). If the method called release on the object right before returning it, it would be returning the address to an object that is already gone. So, there is autorelease, which temporarily delays the release until the calling method can retain the object the called method created.
In your example above, if you got rid of the 2 retains, and only called autorelease, then the object would get released and deallocated when the autorelease pool is released and (right before deallocation) is drained, meaning it calls release on all objects in its pool, tracker being one of them because calling autorelease on tracker added it to the pool.
new is equivalent to doing an "alloc" & "init", so retain count on tracker on that line is 1.
Then you increment the retain count 2 more times to give a total retain count of 3.
Autorelease sets the tracker to be released when the pool is released (and the retain count is decremented as well). But it's already retained 3 times, so it doesn't really get released.
And yeah, there is a memory leak with the retain count being greater than 0 and no reference to "tracker" outside of that method (that is, unless you're using "tracker" in an instance variable).
It's very good to know the basics of memory management; but if you want to save yourself a ton of headache, just do what everyone else here seems to be saying and simply enable ARC.
EDIT: And to finish your question, you should make sure every call to retain is balanced with a release. You also do a "new", which also increments the retain count so you need to "release" because of that as well.

When would you need to call alloc when creating a new object

I understand the whole business around reference counting and "owning an object" and that if you allocate an object in Objective-c, it's your responsibility to release it
However when exactly would you need to call alloc on a newly created object? Would it only be to retain the reference after the end of the scope or is there some other reason
You need to call alloc in order to allocate the memory for the object.
The typical setup of an object is something like:
Object *obj = [[Object alloc] init];
The alloc call allocates memory for the object, and the init call initialises it (gives it sensible default values for all attributes/properties).
Some object types come with factory methods, eg
NSArray *arr = [NSArray array];
In this case, the object is initialised and allocated by the single array call.
None of this has anything (directly) to do with reference counting, except that different ownership rules normally apply to the two methods.
I think you are misunderstanding a basic concept. sending alloc to a class will result in creating a new object of that class (not initialized yet) which you own (retain count will be 1).
from your question "when exactly would you need to call alloc on a newly created object?" -
if the object is newly created it means that someone already allocated it..
if you meant: when do you need to call retain on a newly created object? the answer is if you want to hold it yourself and not rely on whomever allocated it, and might release it sometime.. remember that alloc/new syntax raises the retain count by one, where as other creating methods (like [NSArray array]) return autorelease objects..
in general i would recommend using ARC and not be bothered by these issues..
I'm not exactly a objective-c guy, but I don't think you call alloc on any object, you call it on a class to allocate the object and call init on the newly allocated object.
You may want to retain to retain the reference after the release is performed by autorelease pool, if this is your setup. That often happens to the object created using [NSThing thingWithStuff:stuff] or some such.

Will releasing an array also release its elements?

I alloc my NSMutableArray, and add objects that were alloced as well. Will calling release on my array also release the elements within, or do I have to release each element manually first?
Objects in obj-c collection are released when that collection is deallocated (that's not the same as being released). So in practice if you add your object in collection, collection manages its objects ownership and you don't need to put extra releases for its elements.
Check the Collections Programming Topics guide. More specifically, the
Arrays section and the Array Fundamentals topic:
When an array is deallocated in a managed memory environment, each
element is sent a release message.
So if releasing an array brings its retain count to 0, and it is then about
to be deallocated, at this point the objects will receive a release message.
Otherwise, releasing an array just decrements its retain count as any other
regular object.
Also, when you place objects in the array, they receive a retain message, as
the guide explains.

Do I need to autorelease out parameters of my function ?

I have a method that accepts three NSMutableArrays, one as Input and two as output using pointer to a pointer.
Now I am creating the two arrays inside the method.
So the memory allocation is done inside the method therefore it should be method's responsibility to release the memory.
So should I call autorelease on the objects before assigning them to these output references ?
You can autorelease them. But make sure that, after the method call, you call retain on both the output pointers. Release them once you are done with them
NSMutableArrays *arr1, arr2, arr3;
[self methodOne:arr1 two:*arr2 three:*arr3];
[arr2 retain];
[arr3 retain];
If you allocate or retain an object, you need to release or autorelease it. It's as simple as that.

Obj-C: A reference or a copy?

Is the product item a copy, or just a reference to the object in the NSArray? Does it need to be released? Considering there is no alloc, I assume there is no need for release, correct?
ProductItem *item = [appDelegate.productTextList objectAtIndex:[indexPath row]];
It is a pointer to the ProductItem class.
You should only release an object if you have done something to increase it's retain count. I.e. alloc/init, copy, or call retain.
It's just a pointer of type ProductItem, so it's not a copy.
Your reference is guaranteed to be valid in the scope of the call to objectAtIndex (it calls autorelease on the object). If you want to keep it around for longer you need to retain and are responsible to release it when you are done with it.