Init an object, then store it into an NSArray. Is this going to be a leak? - objective-c

If an inited object comes to me retained, so I own it, and I store it in an NSArray, which retains that which gets stored in it, can I count on NSArray to see that it's already retained and not increase the count, or do I need to run through the array and decrement the retain count to insure no memory leak?

Sounds like you need to read the Memory Management Programming Guide. Your case is extremely simple. You own the object. You pass it to the array, which now also owns it. You need to release your ownership of it. Otherwise you'll leak it.

To make sure that the ownership of the object which was added into the NSArray is relinquished, send the -release message to the object right after you add it to the NSArray. If you do not do this, then you will indeed have a memory leak.
This is what happens:
NSString *str = [[NSString alloc] initWithFormat:#"%#", #"Blah"]; //retain count is 1, you own this object
[array addObject:str]; //retain count gets bumped to 2
[str release]; //retain count is 1 - relinquishing ownership here.
//There is no leak because when the NSArray is
//deallocated, the object will be sent the release message.
But if you don't send the owned inserted object the -release message, then even when the NSArray is deallocated, the object will only have a retain count of 1 and the memory obtained by the object will never be reclaimed, thereby resulting in a leak.

Whenever you release the NSArray, it'll release everything it retains.
As such, as long as you release the inited object once you've added it to the NSArray (so it's the only thing that retains it) or release it once you've finished with it outside of the array all should be fine.
Incidentally, there's a good blog post called "objective-c memory management for lazy people" that explains such things pretty well and is a handy reference if you're just starting out with such things.

You don't need to do that. NSArray takes ownership of any object that it stores. It will release its objects when it's deallocated. If you retain an object yourself, you take ownership too, and you are responsible for releasing it too.

NSArray will retain your object when you add it, and then release it when you remove it from the array. This is by design. This means that to ensure there's no memory leak, if you already retained the object before adding it to the array, you should release it after removing it from the array:
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:10];
NSObject *object = [[NSObject alloc] init]; // retain count of 1 (because of alloc)
[object retain]; // useless, just for example, retain count of 2 (because of retain)
[array addObject:object]; // array is mutable, retain count of 3 (because of addObject:)
[array removeObject:object]; // retain count of 2
[object release]; // retain count of 1
[object release]; // retain count of 0, the object is dealloc'd afterwards
[array release]; // to be sure that we are not leaking an array, too

Related

NSCopying and Objective-C memory management

Apple's NSCopying docs state that copyWithZone: returns an object that's implicitly retained by the sender. So when that object is added to an NSMutableArray it seems like the object should be sent an autorelease message to keep the retain count balanced (since the array will retain the object).
So to deep copy the contents of one array to another I'd expect something like:
NSMutableArray *destination = [NSMutableArray array];
// assume MyObject adopts NSCopying
for (MyObject *obj in myArray)
[destination addObject:[[obj copy] autorelease]];
However I noticed a different approach in this answer. It seems like [ret addObject:[val copy]] is a memory leak. However I'm brand new to NSCopying so I thought I'd ask: When adding a copied object to an array should the object be sent an autorelease message to keep the retain count balanced?
Edit - more info: Clang reports a potential memory leak after removing the autorelease. Perhaps the linked answer assumes copy returns an object that's not implicitly retained by the sender.
Yes it does need to be released but I wouldn't use autorelease in a loop like that, do it manually with each iteration
for (MyObject *obj in myArray)
{
MyObject *copy = [obj copy];
[destination addObject:copy];
[copy release];
}

NSMutableArray in loop leaks memory even when I explicitly release it

This loop leaks memory:
int64_t i,verylongnumber;
//misc. code
for(i=0;i<verylongnumber;i++){
NSMutableArray *myArray = [[NSMutableArray alloc] initWithObjects:
[NSNumber numberWithLongLong:65535],
[NSNumber numberWithLongLong:65535],
[NSNumber numberWithLongLong:65535],
[NSNumber numberWithLongLong:65535],
nil];
[myArray removeAllObjects];
[myArray release];
}
I've tried everything to keep it from leaking memory, but I can't. I think it has something to do with the NSNumbers. I assume they are created autoreleased, but does that mean I have to free them individually (i.e. use alloc)? How would I even do that? Create a separate variable for each NSNumber and insert that into the array? That seems like a lot of work. I tried [myArray removeAllObjects], but that made no difference. it is within my own thread with its own autorelease pool. I'm not sure if that makes a difference.
This fixed it:
I added an additional autorelease pool inside the loop:
int64_t i,verylongnumber;
//misc. code
for(i=0;i<verylongnumber;i++){
NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];
NSMutableArray *myArray = [[NSMutableArray alloc] initWithObjects:
[NSNumber numberWithLongLong:65535],
[NSNumber numberWithLongLong:65535],
[NSNumber numberWithLongLong:65535],
[NSNumber numberWithLongLong:65535],
nil];
[myArray release];
[pool2 drain];
}
I'll take a stab at this..
You can remove [myArray removeAllObjects] as it is redundant. NSArray's do retain their objects, but they also release them when the array itself is deallocated.
The NSNumbers themselves are autoreleased. However if you do a very very large loop then that autoreleased memory won't actually be freed until the for loop exits and eventually the run loop as well (unless you have setup a separate NSAutoreleasePool somewhere).
So I can see how the memory usage would increase as this loop iterates, but at completion it should free the memory. How did you arrive at the conclusion that you have a leak?
Are you waiting to see if the objects get released in the near future?
Autoreleased objects are released at some point in the near future. In the case above, you're looping a very long number of times creating many objects. They will not get released within the scope of that code.
In a GUI app it means after the function returns when the run loop is being run. In a console app, it's when the pool is released.
Check out:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html
Autorelease pools provide a mechanism whereby you can send an object a
“deferred” release message.
The key is the deferred point.
EDIT: (after comment)
Note that you can drain the pool. The other option is to create non-autoreleased numbers (alloc/init) and explicitly release in your long running loop. depending on the code, that may be desirable since draining the pool could release objects deferred for release which code later in that loop/scope assumes is still deferred. If you want to control it, then control it.
NSArray retains objects when they're added to NSArray. This means that NSArray takes ownership of that object. when the object is removed from NSArray or NSArray destroyed, the object is released (reference count -1). If object dont have any other owner then object is destroyed.
The following code will create memory leak
NSNumber *number = [[NSNumber alloc]initWithFloat:floatValue]; //reference count is 1, you are the owner
[aArray addObject:number] //reference count is 2, aArray is also owner.
So to remove memory leak , you shoul release number.
NSNumber *number = [[NSNumber alloc]initWithFloat:floatValue]; //reference count is 1, you are the owner
[aArray addObject:number] //reference count is 2, aArray is also owner.
[number release]; // reference count is 1, you are not owner og number
If you are adding autorelease object to NSArray, no need to release that object. when the autorelease pool is popped that object will loose its ownership.
In your example with each for loop, NSNumber is created while the old one is still hanging around in memory waiting for the autorelease pool to be released.

How to release an object from an Array?

I am currently working on an demo app so I was a little sloppy how to get things done, however I run the "Build and Analyze" to see how many leaks I get,... well and there are a lot.
Source of teh proble is that I have a NSMutableArray and I add some Objects to it :
NSMutableArray *arr = [[NSMutableArray alloc] init];
[arr addObject:[[MyObject alloc] initWithText:#"Option1"]];
// I have like 100 lines like that and 100 complains
Now, xcode complains about a potential leak.
Can someone give me some advice how to handle that ?
Thanks.
The problem is that you're allocating an instance of MyObject which you have a responsibility to release. When you pass it to the array, the array also retains the object, so now both you and the array have to release it. You can simply autorelease the object, and the array will keep it retained until you remove the object from the array or destroy the array itself.
[arr addObject:[[[MyObject alloc] initWithText:#"Option1"]] autorelease];
Replace
[arr addObject:[[MyObject alloc] initWithText:#"Option1"]];
with
[arr addObject:[[[MyObject alloc] initWithText:#"Option1"] autorelease]];
Most collections (arrays, dictionaries) own the objects added to them. And, since you’ve sent +alloc to MyObject, you also own the object that’s just been instantiated. As the memory management rules say, you are responsible for relinquishing ownership of objects you own. Sending -autorelease to the newly instantiated object will do that.

Objective C Array and Object Release

I have a newbie question regarding when to release the elements of a NSArray. See following pseudo code:
NSMutalbeArray *2DArray = [[NSMutableArray alloc] initWithCapacity:10];
for (int i=0;i<10;i++) {
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:5];
for (int j=0;j<5;j++) {
MyObject *obj = [[MyObject alloc] init];
[array addObject:obj];
[obj release];
}
[2DArray addObject:array];
[array release];
}
// use 2DArray to do something
[2DArray release]
My question here is, when I release 2DArray, do I need to explicitly release each of its element (array) first? Also, before I release the "array" object, do I need to release each of its element (MyObject) first?
I am new to Objective C. Please help. thanks.
No, you don't need to tell each object to be released. When you send a release method to an NSArray, it automatically sends a release method to each item inside first.
So in your case, you send [2DArray release]. This automatically sends [array release] to every other array, which sends [obj release] to each object inside each array.
You don't need to release the kept objects. NSArray retains them when you add, and releases them when released. So if you allocate, add to the array, then release, the object in the array will have the retain count of 1. Once the array is freed, the object is released, therefore freed.
When an object is created, it has a retain count of 1. Whenever a object is added to an array, its retain count is increased (in this case to 2). After adding to the array, your code release its hold of the object, dropping its retain count by 1 (to 1 in this case). Then when you release the array, it calls release on everything in it dropping their retain counts by 1 (to 0 in this case). When retain count hits 0 the object is deallocated.
Your code looks correct from a memory management stand point.

Who is responsible for releasing objects in an array when copying?

In Objective-C, if array1 is copied onto array2 using mutableCopy, and suppose the code is done in main(), who is responsible for releasing the objects contained in the array? Is it main() or array2?
I think the previous answers have missed the point, or else the asker was pretty unclear. The actual question isn't talking about either array, but rather the array contents:
who is responsible for releasing the objects contained in the array? Is it main() or array2?
Both array1 and array2 are responsible for releasing the objects.
From the NSArray documentation:
"Arrays maintain strong references to their contents—in a managed memory environment, each object receives a retain message before its id is added to the array and a release message when it is removed from the array or when the array is deallocated."
To begin with, each of the objects are retained by the NSArray array1. When you create array2 via -mutableCopy, you get an NSMutableArray which points to the same objects, and retains each of them again. If you were to release array1 at this point, when its dealloc method were called it would release each of the objects it contains. However, array2 has retained them, so the objects won't be destroyed — only when their retain count reaches 0, which would happen if array2 were destroyed and nobody else has retained any of the objects (or when they are removed from array2).
Since collection classes (arrays, sets, dictionaries, etc.) handle retaining and releasing their contents, all you have to worry about is retaining or releasing the collection itself. Since you used -mutableCopy, remember that you have implicitly retained array2, so you should release it when you're done with it.
I reference this guide for Memory Management in Obj-C. He has a section on Arrays and Dictionaries, here's an excerpt:
Arrays, dictionaries etc. generally retain any objects added to them. (When dealing with 3rd party collection type objects, always check the documentation to see if they retain or not). This means that these collections will take ownership of the object, and you do not need to retain before adding.
The comments for the posting are also useful
The ownership responsibilities are not changed by storing objects in an array. Here's an example:
int main(int argc, char *argv[])
{
// ...
NSObject *obj1 = [[NSObject alloc] init]; // owned
NSObject *obj2 = [[NSObject alloc] init]; // owned
NSObject *obj3 = [[[NSObject alloc] init] autorelease]; // not owned
NSMutableArray *array1 = [NSMutableArray arrayWithObjects: obj1, obj2, obj3, nil]; // not owned
NSMutableArray *array2 = [array1 mutableCopy]; // owned
// ...
[array2 release];
[obj2 release];
[obj1 release];
// ...
}
This code directly allocates obj1 and obj2, so it owns them and must release them, but it autoreleases obj3, so it doesn't have to release that. In the same way, it doesn't own the result of arrayWithObjects:, so it doesn't release that, but it does own the result of mutableCopy, so it must release that. The objects being stored in an array is irrelevant—all you need to care about is ownership.
Both arrays keep strong references to their content, so obj1, obj2, and obj3 won't be deallocated as long as the arrays exist—but that's a detail of the NSArray contract, it doesn't affect how you manage the ownership of the objects or the arrays.
These are all details of Cocoa's memory management conventions, not arrays.
It wouldn't make sense for a mutable array to be tied to an immutable array. main() would be responsible for releasing array1.
In my experience however, releasing objects only causes applications to crash. ObjC is fairly good at automatically managing memory. My Cocoa apps don't seem to ever need more memory than they started with, even after running several hours.