Objective C release, autorelease, and data types - iphone

I'm new to memory managed code but I get the idea pretty well.
On taking my app through the leaks tool in XCode, I noticed I only had to clean up my custom objects, but not dynamically created arrays for example, so I figured those data types are autoreleased - makes sense since I only had to release the arrays I used as properties that had a (retain) on them.
Then I noticed something peculiar : I was getting a leak on a certain array initialized like this :
NSMutableArray *removals = [NSMutableArray new];
but not a similar one
NSMutableArray *removals = [NSMutableArray arrayWithCapacity:9];
Now, the reason one was set up with "new" is that it could have 0-99 items in it, whereas the other one I knew was going to always be 9. Since both arrays are passed to the same method later based on user interaction, I was either getting a leak if I did not release at the end of the method, or an exception if I did!
I changed the first array to
NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];
and I get no leaks and don't have to release anything. Can anyone explain?

As noted in the memory management rules, whenever you have an object that you have created with +alloc, +new, -copy, or -mutableCopy, you own it and are responsible for releasing it at some point. (In fact, +new is just shorthand for [[MyClass alloc] init].) As you noted, creating an array via [NSArray new] without releasing it is a memory leak. However, if you handle this object properly, it is usually possible to release it at some point. For example:
If the method that uses the array is called from within the method that creates the array, then you should be able to release the array after it has been used. If the inner method needs to keep a more permanent reference to the array around, then that method is responsible for sending -retain and, eventually, -release to the object. For example:
- (void)myMethod {
NSArray *removals = [NSArray new];
// ...
[someObject someOtherMethod:removals];
[removals release];
}
If you created the array in an -init method for an object, then the -dealloc method can release it when the object is destroyed.
If you need to create the array and then return it from the method, you've discovered the reason that autoreleasing was invented. The caller of your method isn't responsible for releasing the object, since it isn't an +alloc, +new, -copy, or -mutableCopy method, but you need to ensure it is released eventually. In this case, you manually call -autorelease on the object before you return it. For example:
- (NSArray *)myMethod {
NSArray *removals = [NSArray new];
// ...
return [removals autorelease];
}
When you create the array via +arrayWithCapacity:, you aren't calling one of the "special" methods, so you do not have to release the result. This is probably implemented with -autorelease, much like the last example above, but not necessarily. (Incidentally, you can also create an empty autoreleased NSMutableArray with [NSMutableArray array]; the method is found in NSArray, so it won't show up in the documentation under NSMutableArray, but it will create a mutable array when sent to the NSMutableArray class.) If you're going to be returning the array from your method, you can use this as shorthand for [[[NSMutableArray alloc] init] autorelease]—but it is just a shortcut. In many situations, though, you can create an object with -init or +new and manually release it at the appropriate time.

This is how things implemented behind the scene:
+(NSMutableArray*) new
{
return [[NSMutableArray alloc] init];
}
and
+(NSMutableArray*) arrayWithCapacity:(NSNumber)capacity
{
return [[NSMutableArray alloc] initWithCapacity:capacity] **autorelease**];
}
In first case the array is allocated only and you're responsible for de-allocating it. In contrary the arrayWithCapacity has autoreleased for you and won't cause leak even you forget to deallocate.

Cocoa uses certain naming conventions. Anything that starts with alloc, new, or copy returns something with a retainCount of 1 and you are required to release. Anything else that a function returns has a balanced retainCount (it might be held by something else, or it might be retained and out released).
So:
NSMutableArray *removals = [NSMutableArray new];
Has a retainCount of 1, and:
NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];
or
NSMutableArray *removals = [NSMutableArray array];
Don't since the methods are not prefixed with alloc, new or copy. This is all spelled out in the memory management documentation. In particular:
You take ownership of an object if you
create it using a method whose name
begins with “alloc” or “new” or
contains “copy” (for example, alloc,
newObject, or mutableCopy), or if you
send it a retain message. You are
responsible for relinquishing
ownership of objects you own using
release or autorelease. Any other time
you receive an object, you must not
release it.

Related

How does calling retain in different ways on the same object work?

I want to know difference between following two:
NSMutableArray *myArray = [[someObject returnMutableArray] retain];
and
NSMutableArray *myArray = [someObject returnMutableArray];
[myArray retain];
I have some complex data flow project in which I have to return different NSMutableArrays.
I also want to know what is the best way to return NSMutableArrays.
There is no difference apart from how you want your code formatted.
The reason this works is in the documentation for NSObject
As a convenience, retain returns self because it may be used in nested expressions.
Therefore retain returns the object that is was called upon (a mutable array in your case) which means you can nest methods or simply use the return value in the assignment as you have in your example.
For returning values from methods you should make sure it is autorelease'd
So using your snippet
- (NSMutableArray *)myMethod;
{
NSMutableArray *myArray = [someObject returnMutableArray];
// ... do some work
return myArray;
}
Because the method returnMutableArray does not contain the keyword's alloc, new or copy it should be made to return an autorelease'd object. Now as we are returning the object at the end of the method we don't need to take any further retains as it will be ready for returning.
If you are unsure on memory management you should read the Advanced Memory Management Guide or (preferably) start using ARC
There is no difference between 1 and 2.
The best practice on iOS is to return autoreleased objects from methods, and there should be no need to retain them.
If you are confused about how retain and release work, you should probably just enable ARC in your project, which manages retain and release for you automatically.

Correct use of autorelease

I am trying to understand why my application crashes and I am going through my code. I am pretty sure that this is a valid use of autorelease:
(part of the code)
- (NSArray *)allQuestionsFromCategories:(NSArray *)categories {
...
NSMutableArray *ids = [[[NSMutableArray alloc] init] autorelease];
while (sqlite3_step(statement) == SQLITE_ROW) {
[ids addObject:[NSNumber numberWithInt:sqlite3_column_int(statement, 0)]];
}
return [NSArray arrayWithArray:ids];
}
Is this valid? The NSArray arrayWithArray returns an autorelease object doesn't it? I also have some difficulties in understanding the scope of autoreleased objects. Would the autoreleased object (if it is in this case) be retained by the pool through out the method that invoked the method that this code is a part of?
- (void)codeThatInvokesTheCodeAbove {
NSArray *array = [self.dao allQuestionsFromCategories];
...
}
Would the array returned be valid in the whole codeThatInvokesTheCodeAbove method without retaining it? And if it was, would it be valid even longer?
Got some issues understanding the scope of it, and when I should retain an autorelease object.
That is valid, but -- really -- you can just skip the [NSArray arrayWithArray:ids]; entirely as there is no need to create a new array.
An autoreleased object is valid until the autorelease pool is drained, which typically happens once per pass through a run loop (or "periodically, but never while your block is executing" when enqueuing stuff via GCD).
The documentation explains it all better than I.
There is no need to create an immutable array because the return will effectively "up cast" the NSMutableArray to NSArray. While this is meaningless at run time, it means that the caller cannot compile a call to a mutating method of the returned value without using a cast to avoid the warning. Casting to avoid warnings in this context is the epitome of evil and no competent developer would do that.
If it were an instance variable being returned then, yes, creating an immutable copy is critical to avoid subsequent mutations "escaping" unexpectedly.
Have you read the memory management documentation? Specifically, the part about autorelease pools? It makes it quite clear how autorelease works. I hate to paraphrase a definitive work.
[NSArray arrayWithArray:] returns an autoreleased object. If you want codeThatInvokesTheCodeAbove to take ownership of the array, you should call retain on it (and rename codeThatInvokesTheCodeAbove according to apple's guidelines). Otherwise, if you don't care that ownership of the object is ambiguous then your code is okay.
In other words, [NSArray arrayWithArray:] returns an array that you don't own, but you have access to it for at least this run cycle. Therefore, codeThatInvokesTheCodeAbove will have access to it for at least this run cycle. Ownership is not clear, since nobody called alloc, copy, new, or mutableCopy or retain. It is implied that NSArray called autorelease before returning the new array, thus relinquishing ownership.
My information comes from http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html%23//apple_ref/doc/uid/20000994-BAJHFBGH.
So, to answer your question, yes your posted code is valid. Whether it's correct depends on what it is you are trying to accomplish.
Autoreleased object are objects that are marked as to be release later.
There is a very particular object that is automatically created by UIApplicationMain: an UIRunLoop.
Imagine it like a while structure, it cycle until application is terminate, it receives every event and properly resend it to your interested classes, for example. Just before UIApplicationMain there is a command to create an NSAutoreleasePool that, once the NSRunLoop is ready, attach to it. When you send an -autorelease command to an object, the NSAutoreleasePool will remember to release it when is released itself. It's dangerous to use it many times in platforms that has less memory (iOS devices), because objects aren't released when you send an -autorelease command but when the NSAutoreleasePool is drained (when app releases it).
If you want to free the non-mutable list before you return, you can use something like this:
- (NSArray *)allQuestionsFromCategories:(NSArray *)categories {
...
NSArray* result;
NSMutableArray *ids = [[NSMutableArray alloc] init]; // AUTORELEASE REMOVED FROM HERE
while (sqlite3_step(statement) == SQLITE_ROW) {
[ids addObject:[NSNumber numberWithInt:sqlite3_column_int(statement, 0)]];
}
result = [NSArray arrayWithArray:ids]; // COPY LIST BEFORE IT IS FREED.
[ids release]; // MUTABLE LIST FREES _NOW_
return result; // NONMUTABLE COPY IS RETURNED
}
It is not worth doing this unless your mutable array is likely to sometimes use a lot of memory.

TablewView example in Beginning iPhone book

This is probably a dumb question, but in the introduction to TableViews, the author has a property of NSArray *listData to fill the table with dummy data. In the viewDidLoad, he basically does this:
- (void)viewDidLoad {
NSArray *array = [[NSArray alloc] initWithObjects#"1", #"2", #"3", more stuff, nil];
self.listData = array;
[array release];
...
}
Why does he create another array and set it to the property as opposed to doing something like
- (void)viewDidLoad {
listData = [[[NSArray alloc] initWithObjects#"1", #"2", #"3", more stuff, nil]autorelease];
Is it to manage memory better by using alloc/init vs the autorelease pool? Or is the second way just not going to work? Thanks.
Your code is wrong and is likely to crash. In his code, he calls alloc, meaning the retain count is 1. He then assigns it to a property. I'm assuming this property is declared to be retain, in which case the retain count would go up to 2. He then called release, which drops the retain count back to 1.
In your code, you call alloc, meaning the retain count is 1, then you call autorelease, which means that the retain count will drop to 0 and the object's memory will be deallocated soon. You assign the object to an instance variable - not a retained property like he does - so you won't increase the retain count any more. This means that you'll be left with a dangling pointer to memory that could be overwritten with anything else at any time. When you try to access listData, you'll crash because it is likely to have been overwritten.
Please read Memory Management Programming Guide if you do not understand what is happening here.
Having said that, the core of your question is valid. There's nothing stopping him from doing the same as you, except assigning to a retained property instead of an instance variable.

Difference between [NSMutableArray array] vs [[NSMutableArray alloc] init]

can someone tell me the difference in declare an mutable array with:
NSMutableArray *array = [NSMutableArray array];
and
NSMutableArray *array = [[NSMutableArray alloc] init];
Because in the beginning I was declaring all my arrays with alloc, and if in the end of a certain function I returned the array created with alloc, I had to autorelease that array, because of memory leak problems.
Now using the first declaration I don't need to release anything.
Thanks
The array class method by itself produces an autoreleased array, meaning you don't have to (and should not) release it manually.
Because in the beginning i was declaring all my arrays with alloc and if in the end of a certain function i returned the array created with alloc i had to autorelease that array, because memory leak problems. Now using the first declaration i don't need to release anything
That is exactly correct when you "vend" an object. But in other cases, when you create an object on iOS, where you have a choice between obtaining a ready-made autoreleased object and calling alloc followed by release, Apple wants you to use alloc and release, because this keeps the lifetime of the object short and under your control.
The problem here is that autoreleased objects live in the autorelease pool and can pile up until the pool is drained, whenever that may be.
Another thing to watch out for is loops. You may generate autoreleased objects without being aware of it, and they just pile up in the pool. The solution is to create your own autorelease pool at the start of the loop and release it at the end of the loop, so that the objects are released each time thru the loop.
EDIT - 12/18/2011: But with iOS 5 and the coming of ARC, the autorelease mechanism is far more efficient, and there is no such thing as release, so the distinction between alloc-init and a convenience constructor vending an autoreleased object becomes moot. (Also it's now an #autoreleasepool block rather than an autorelease pool (pseudo-)object.)

insertObject doesn't add object?

I'm trying to grope my way through Obj-C to build an iPhone game.
I'd like to build an array of objects for later use. Here's what I tried:
NSMutableArray *positionIcons;
[positionIcons insertObject:annotation atIndex:0];
positionIcons = [NSArray arrayWithObjects:annotation, nil];
The insertObject line leaves the count at 0. However, the next line correctly inserts the object (and count moves to 1). What gives?
You need to initialize positionIcons, change the code to:
NSMutableArray *positionIcons = [[NSMutableArray alloc] init];
[positionIcons insertObject:annotation atIndex:0];
positionIcons = [NSArray arrayWithObjects:annotation, nil];
#msaeed has the right answer, but it's worth taking a little more time on that code fragment, because it leaks memory.
The iPhone doesn't support garbage collection, so it's important to understand how Objective-C's semi-automatic memory management works. Apple has a good reference here, but the gist of it is that you are responsible for maintaining the "retain count" of your objects. When initializing an object with an -init instance method (such as [[NSMutableArray alloc] init] in your example, but also any other method starting with "init", like [[NSMutableArray alloc] initWithCapacity:42], the newly-initialized object has a retain count of 1. Subsequent calls to that instance's -retain method increment the retain count, while calls to the instance's -release method decrement the count. When the count reaches 0, the object is deallocated, and further attempts to send it messages will result in null pointer exceptions.
In the case of #msaeed's corrected code, here's what's happening, by line:
A new instance of NSMutableArray is allocated; the -init method is called, which initializes the instance and sets the retain count to 1. The positionIcons pointer is then set to the address of this new instance.
The -insertObject:atIndex: method is called on positionIcons, and all is well (also, by convention adding an object to a collection like NSMutableArray increments that object's retain count, the idea being that the collection now has, in some sense, "ownership" of that object, and doesn't want it to be deallocated from underneath it).
A new instance of NSArray is allocated, and the positionIcons pointer is then set to the address of that new instance. Because the retain count of the NSMutableArray from line one is still 1, it will not be deallocated, and since you've lost your reference to it, you can never call -release on it to clear it out of memory. There's your leak.
By convention, there's a difference in how you manage objects that are initialized with -init instance methods versus class methods like +arrayWithObjects: (in the first case, you have to release the object yourself, but in the second case, the object has already been sent an -autorelease message and will be deallocated on the next pass through the program's runloop unless you call -retain on it.