Hi I have a lot of problems to remove the objects of my mutable array.
I have a method which send back a mutable initialized with a custom object.
This mutable is declared like autorelease for releasing after method.
In my return, I retain the mutable to not loose it.
I want in this second method to remove the content of my mutable and release my mutable.
But my app quit and fail.
//first method which return my mutable
NSMutableArray *highScores = [[[NSMutableArray alloc] init]autorelease] ;
for (....)
{
HighScore *currentHighScore = [[HighScore alloc] init];
currentHighScore.user = name;
currentHighScore.score = score;
//add to the array
[highScores addObject:currentHighScore];
[currentHighScore release];
}
return highScores;
// method which use the first method
//retrieve with retain to keep.
highScoreList = [[HighScoreViewController getHighScores:NormalGameModeXML]retain] ;
HighScore *currentHighScore;
int count = [highScoreList count];
for (int i = 0; i < count ; i++)
{
currentHighScore = [highScoreList objectAtIndex:i];
}
This is working, but off course I have memory leak for all the objects in the mutable not released.
But if i'm trying to release the object of the mutable and the mutable itself by this :
//remove Mutable array content.
//[highScoreList removeAllObjects] ;
//[highScoreList release];
My app is quitting.
Do you have a solution to avoid the memory leak and clean it well?
Try using NSZombieEnabled to check the reason for an EXC_BAD_ACCESS..
HowTo is found here..
//[highScoreList removeAllObjects] ;
//[highScoreList release];
No need to removeAllObjects prior to release.
Note that if you use highScoreList after it is deallocated, your app will crash as you describe. I.e. if you use highScoreList after the above, BOOM.
You could set highScoreList to nil, but a better solution is to understand why you are using an object after you think you should be done with it.
And, as always:
If there is a crash, there is a backtrace. Post it.
Related
If I have an NSMutableArray of custom objects, how can I must easily clear the array without causing any memory issues? Assume that the custom object class has a dealloc method in it which correctly released an instance variables etc.
For example is it ok to use the NSArray "removeAllObjects" method?
If yes - how does this work - does "removeAllObjects" call the "dealloc" method on each object as it removes them
If no - what would be the easiest approach to use?
EDIT (after 4 replies) - One last question of clarification after the great replies - I'm still not quite sure about the instance variables/properties in my custom object that I have set to retain? These seem to be only released via the the "dealloc" method in my custom object class, where we do this manually along with [super release].
So if, re clearing an array, if I do a removeAllObjects, and then NSArray issues a "release" to my custom objects, but doesn't call "dealloc", then how do my instance variables get released?
removeAllObjects will remove the object from the array. This process will send a release message to the object and this will decrease its reference count. When the reference count reaches zero the object will be deallocated.
don't do it like this, because it will leak.
NSObject *object = [[NSObject alloc] init]; + 1
[array addObject:object]; + 1
[array removeAllObjects]; - 1
=======
= + 1 -> Leak
this is the correct way:
NSObject *object = [[[NSObject alloc] init] autorelease]; + 1 (from alloc) - 1 (from autorelease)
[array addObject:object]; + 1
[array removeAllObjects]; - 1
=======
= 0 -> Object will be deallocated
Instead of calling removeAllObjects you could just release the array. If an array is deallocated everything that's inside of it gets released and if there is no other reference to the object it will be deallocated.
Yep, just call removeAllObjects. Just to be sure, you don't call retain when you add an object to an array or when you create an array with objects. That's done for you automatically.
Regarding dealloc, again that will be done automatically, and you can't predict when.
The only thing you need to have in the dealloc is the array object itself. That is, assuming it's an instance variable or ivar?
To check everything is good, run the Analyzer using Product -> Analyze. And then give the app a profile in Instruments using the Leaks instrument to check that none of your code is causing any memory leaks.
Basically removeAllObjects method sends release message to all the objects. The release method decrements the objects reference count. And if the reference count of an object reaches 0 then the dealloc message will be sent to the object.
The answer to your question is calling [array removeAllObjects] is completely safe. By the way if you don't want the array anymore you can directly call [array release] which releases all its objects as well as the array.
The dealloc method is never called directly. Everything is done thru the retain/release mechanism (and the reference counting principle). So this is the release method that gets called, not the dealloc directly. The dealloc method is only called by the runtime if the last release call causes the reference counting (retainCount) of the object reaches zero, meaning that the object really is deallocated from memory as noone uses it anymore.
NSArray and all container classes in Cocoa (NSDictionary, NSSet, ...) do retain their values. So when you add an objet to a container like NSArray, it will retain that value. And when you remove that value (including when you call removeAllObjects") it will release it.
Memory Mgmt rules are easy to follow: but the only rule that matters it that you only have to call release or autorelease if you called alloc, retain or copy methods. That's always the responsability of the objet which did the alloc/retain/copy to call the release/autorelease. Never leave a alloc/retain/copy without a pending release/autorelease call to balance it (or you will have leaks), but on the other hand never call release/autorelease if you didn't do the alloc/retain/copy call yourself.
Good example 1:
MyClass* obj = [[MyClass alloc] init]; // here you do an alloc
[myArray addObject:obj]; // the NSArray "myArray" retains the object obj
// so now you can release it, the array has the responsability of the object while it is held in the array
[obj release]; // this release balance the "alloc" on the first line, so that's good
[myArray removeAllObjects]; // there the object held by the array receive a release while being removed from the array. As nobody retains it anymore, its dealloc method will be called automatically.
Good example 2:
MyClass* obj = [[MyClass alloc] init]; // here you do an alloc
[myArray addObject:obj]; // the NSArray "myArray" retains the object obj
// so now you can release it, the array has the responsability of the object while it is held in the array
[myArray removeAllObjects]; // there the object held by the array receive a release while being removed from the array. But your own code still retains a reference to it (because of the "alloc" on first line) so it won't be removed from memory right now
[obj release]; // this release balance the "alloc" on the first line, and as nobody retains the object anymore, its dealloc method will be called and it will be deallocated from memory
Good example 3:
MyClass* obj = [self getSomeObjectFromAnotherMethod]; // here you don't have an "alloc" on this line
[myArray addObject:obj]; // the array retains the object
[myArray removeAllObjects]; // the array release the object while it removes it from the array
// no need to call "release" here as there is no "alloc" done in the scope of this code
Bad example:
MyClass* obj = [self getSomeObjectFromAnotherMethod]; // here you don't have an "alloc" on this line
[myArray addObject:obj]; // the array retains the object
[myArray removeAllObjects]; // the array release the object while it removes it from the array
[obj release]; // Crash here! obj does not exists anymore and has been deallocated from memory before this line!
I'm new to cocoa / objective-c and i'm struggeling with the releases of my objects. I have the following code:
gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
NSString *oid = [gastrocategory objectForKey:#"id"];
GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:#"name"]];
[gastroCategoryList addObject:gc];
}
The analyzer shows me that the "gastrocategory" defined in the for is a potential memory leak. But i'm not sure if i can release this at the end of the for loop?
Also at the following code:
- (NSArray *)eventsForStage:(int)stageId {
NSMutableArray *result = [[NSMutableArray alloc] init];
for (Event *e in eventList) {
if ([e stageId] == stageId) {
[result addObject:e];
}
}
return result;
}
The Analyzer tells me that my "result" is a potential leak. But where should I release this?
Is there also a simple rule to memorize when i should use assign, copy, retain etc. at the #property ?
Another problem:
- (IBAction)showHungryView:(id)sender {
GastroCategoriesView *gastroCategoriesView = [[GastroCategoriesView alloc] initWithNibName:#"GastroCategoriesView" bundle:nil];
[gastroCategoriesView setDataManager:dataManager];
UIView *currentView = [self view];
UIView *window = [currentView superview];
UIView *gastroView = [gastroCategoriesView view];
[window addSubview:gastroView];
CGRect pageFrame = currentView.frame;
CGFloat pageWidth = pageFrame.size.width;
gastroView.frame = CGRectOffset(pageFrame,pageWidth,0);
[UIView beginAnimations:nil context:NULL];
currentView.frame = CGRectOffset(pageFrame,-pageWidth,0);
gastroView.frame = pageFrame;
[UIView commitAnimations];
//[gastroCategoriesView release];
}
I don't get it, the "gastroCategoriesView" is a potential leak. I tried to release it at the end or with autorelease but neither works fine. Everytime I call the method my app is terminating. Thank you very much again!
In your loop, release each gc after adding it to the list since you won't need it in your loop scope anymore:
gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
NSString *oid = [gastrocategory objectForKey:#"id"];
GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:#"name"]];
[gastroCategoryList addObject:gc];
[gc release];
}
In your method, declare result to be autoreleased to absolve ownership of it from your method:
NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];
// An alternative to the above, produces an empty autoreleased array
NSMutableArray *result = [NSMutableArray array];
EDIT: in your third issue, you can't release your view controller because its view is being used by the window. Setting it to autorelease also causes the same fate, only delayed.
You'll have to retain your GastroCategoriesView controller somewhere, e.g. in an instance variable of your app delegate.
BoltClock's answer is spot-on as to the first part of your question. I'll try to tackle the rest.
Assign is for simple, non-object types such as int, double, or struct. It generates a setter that does a plain old assignment, as in "foo = newFoo". Copy & retain will, as their names imply, either make a copy of the new value ("foo = [newFoo copy]") or retain it ("foo = [newFoo retain]"). In both cases, the setter will release the old value as appropriate.
So the question is, when to copy and when to retain. The answer is... it depends. How does your class use the new value? Will your class break if some other code modifies the incoming object? Say, for example, you have an NSString* property imaginatively named "theString." Other code can assign an NSMutableString instance to theString - that's legal, because it's an NSString subclass. But that other code might also keep its own reference to the mutable string object, and change its value - is your code prepared to deal with that possibility? If not, it should make its own copy, which the other code can't change.
On the other hand, if your own code makes no assumptions about whether theString might have been changed, and works just as well whether or not it was, then you'd save memory by retaining the incoming object instead of unnecessarily making a copy of it.
Basically, the rule, which is unfortunately not so simple sometimes, is to think carefully about whether your own code needs its own private copy, or can correctly deal with a shared object whose value might be changed by other code.
The reason you can release gc after it is added to the gastroCategoryList is that when an object is added to an array, the array retains that object. So, even though you release your gc, it will still be around; retained by the gastroCategoryList.
When you are returning a newly created object from a method, you need to call autorelease. This will cause the object to be released only after the runtime leaves the scope of the calling method, thereby giving the calling method a chance to do something with the returned value.
Note that if your method starts with the word copy or new, then you should not autorelease your object; you should leave it for the calling method to release.
As for copy vs retain vs assign... as a general rule, copy objects that have a mutable version, such as NSArray, NSSet, NSDictionary, and NSString. This will ensure that the object you have a pointer to is not mutable when you don't want it to be.
Otherwise, use retain whenever you want your class to be ensured that an object is still in memory. This will apply to almost every object except for objects that are considered parents of your object, in which case you would use assign. (See the section on retain cycles here).
Also note that you have to use assign for non-object types such as int.
Read through the Memory Management Programming Guide a bit; it's quite helpful.
I have been very confused on how to handle the releasing of an NSMutableArray when I need to return it from a method. I am not even sure if I am suppose to release it or not.
I have the code:
-(NSArray *)methodToCall {
NSMutableArray *mutArray = [[NSMutableArray alloc] initWithCapacity:10];
//Fill the array with stuff here
[mutArray release]; //Am I suppose to have this to keep the memory down?
return mutArray;
}
My question is whether or not I am suppose to have the [mutArray release]; in the code or not. Could someone explain this? I am at a loss and I want to keep my code as clean and leak free as possible.
The caller of your method is going to expect a valid NSArray, but which it doesn't own.
If you release it the way you're doing in your question, you're returning an invalid object (because you've both allocated and released it.) So that's not what you want.
You should "autorelease" the array before returning it. Then you'll be allocating it, but relinquishing ownership (without forcibly releasing it) before returning it. It will be valid until the end of the current event loop when the autorelease pool gets cleaned up, and your caller can retain it or let it go as appropriate:
-(NSArray *)methodToCall {
NSMutableArray *mutArray = [[NSMutableArray alloc] initWithCapacity:10];
//Fill the array with stuff here
return [mutArray autorelease];
}
Your other alternative, since you don't need to keep the reference around either, is to use one of the "autoreleasing" convenience methods to create it in the first place:
-(NSArray *)methodToCall {
// We're not doing an explicit alloc/init here, so...
NSMutableArray *mutArray = [NSMutableArray arrayWithCapacity:10];
// ...no autorelease necessary.
return mutArray;
}
Short answer - No.
As it is now, you are allocating an array and then releasing (freeing) it before the return. So the when you try accessing the return object from your calling method you're going to get a crash.
My suggestion would be to use autorelease or to have the calling method or class ivar be responsible for this array object if it is used often.
An example of the autorelease:
NSMutableArray *mutArray = [[[NSMutableArray alloc] initWithCapacity:10] autorelease];
I also suggest reading the Memory Management from the Developer Documents.
if you go for explicit object allocation by calling alloc and init you are owner of your object, so you are responsible for its object retain value else you do it by implicit you don't need to care about it. it will take care of itself.
-(NSMutableArray *)getArray
{
NSMutableArray *array=[[NSMutableArray alloc] initWithCapacity:10];
//your code
return [array autorelease];
}
in the above code we are the owner of the object so we need to handle its retain count by passing autorelease the autoreleasepool will take care of it.
-(NSMutableArray *)getArray
{
NSMutableArray *array=[NSMutableArray allocWithCapacity:10];
//your code
return array;
}
in the above code we didn't alloc any object we just call class method to define the size of the array.
if you want more details go for the object ownership in Memory management guide from apple library
In general, instead of using alloc/init to create a temporary array, consider using a convenience creation method (+arrayWithCapacity: in this case):
- (NSArray *)methodToCall
{
NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:10];
// Fill the array with stuff here
return mutableArray;
}
Convenience creation methods such as +arrayWithCapacity: return an object that the caller is not responsible for, relieving the calling code of the burden of managing memory. Since the calling code is simply returning the reference rather than storing it, that'll simplify things.
I try to understand the memory management in ObjectiveC and still some things are a misery for me.
I've got an instance variable:
NSMutableArray *postResultsArray;
when a button is clicked in the UI I create new array:
self.postResultsArray = [NSMutableArray array];
then I add some objects to the array and when the whole operation is done I would like to release the array:
[self.postResultsArray release];
(I assume that all the objects stoed in the array will be released along with the array).
The problem appears when I click the button again and in the code I want to create the array again with:
self.postResultsArray = [NSMutableArray array];
I get:
[CFArray release]: message sent to deallocated instance 0x3d9e390
Can't I initialize the same instance variable for the second time? or maybe I should not release it? and if so, why?
Thanks!
Don't to this:
[self.postResultsArray release];
When you do this, the ivar is still assigned to the old array's memory address. If you want to release the array, there are two safe ways to do it:
[postResultsArray release];
postResultsArray = nil;
Or
self.postResultsArray = nil;
What's happening is that the code for setting the postResultsArray looks like this (paraphrase, not exact):
-(void)setPostResultsArray:(NSMutableArray *)newArray {
[array retain];
[postResultsArray release]; // this is what's causing the the deallocation message in your log
postResultsArray = array;
}
You shouldn't manually release an object that is accessed through a property. Instead of
[self.postResultsArray release];
do
self.postResultsArray = nil;
and all will be fine. The setter will release the old array and then assign nil to the pointer. What is happening now is that the setter is trying to release the old array when you assign a new array to the property, but you have already released that array, hence the error.
Don't do [self.postResultsArray release];, do self.postResultsArray = nil, this has to do with the implementation of properties. They will automatically release whatever is currently stored and retain the new value.
You only need to call release if you create an object with one of the "init" messages or explicitely call retain yourself. Since you do neither you don't need to call release as the code that created the array will be handling the release - most probably by using autorelease.
I have this code in one of my classes:
- (void) processArray
{
NSMutableArray* array = [self getArray];
. . .
[array release];
array = nil;
}
- (NSMutableArray*) getArray
{
//NO 1:
NSMutableArray* array = [[NSMutableArray alloc]init];
//NO 2:
NSMutableArray* array = [NSMutableArray array];
. . .
return array;
}
NO 1: I create an array and return it. In the processArray method I release it.
NO 2: I get an array by simply calling array. As I'm not owner of this, I don't need to release it in the processArray method.
Which is the best alternative, NO 1 or NO 2? Or is there a better solution for this?
The method should return an autoreleased array, NO 2 is the better choice. The reason for this is that when you call the method with
NSMutableArray* array = [self getArray];
you will expect as a matter of convention to not have to release the array. If you want to take ownership of it, you retain it, but otherwise you shouldn't have to care about it. In Cocoa, you only take ownership by explicitly sending alloc or retain or copy (or new). Since the processArray method doesn't do that, it shouldn't have to take care of releasing the array.
So you should use NO 2, and also you should remove these two lines:
[array release];
array = nil;
If the array and its contents use a lot of memory or its used lots of times, you'll want to release them straight away, so use option 1. According to the Objective-C guidelines, you'll want to prefix the word "new" to your subroutine name instead of "get" in that case.
If on the other hand, you want to reduce the number of lines of code that say simply [array release]; or similar then use option 2.
It is simply a balance between reducing lines of code, and reducing unnecessary temporary memory use.
Whilst the autorelease pool will help in reducing memory leaks and make your code smaller, sometimes you need to explicitly release everything as it goes out of use to keep the use of memory down.
HTH
EDIT
Ah - I stand corrected. Reading the iPhone version of the Memory Management Programming Guide for Cocoa I see that the iPhone guidelines are to use a prefix of "new..." so for example "newArray" in this case, if the caller is supposed to manually release and NOT a prefix of "create...". "Creating" can refer either to creation of manually released or of automatically released objects and so would be ambiguous. Text corrected above.
- (void) processArray
{
NSMutableArray* array = [[self getArray] retain];
//Now you are the owner of array, so you take care to release it
. . .
[array release];
array = nil;
}
- (NSMutableArray*) getArray
{
//create a new array
//temporarily the method owns the array
NSMutableArray* array = [[NSMutableArray alloc]init];
//fill in here with elements or what you want
..........
[array autorelease];
//autorelease here says "I don't own the result
//if anyone cares about it, he should retain it himself
return array;
}
So in short when you create new objects you should autorelease them before returning.
Because if the calling method wants to use the result, the calling method should take care
of retaining and releasing the result.
It's always good to run the Klang static analyzer for this issues, when you are not really sure in your retaining/releasing code : http://clang-analyzer.llvm.org/