Can a variable bu used 2nd time after releasing it? - iphone

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.

Related

Why can I not initialise my variable without using self

I have the following variable defined:
#property (nonatomic, retain) NSMutableArray *arraySpeechSentences;
And I am trying to initialise it in the following way:
// Set the array of sentences to the stored array
NSMutableArray *speechSentences = [[NSMutableArray alloc] initWithArray:[tempDict objectForKey:key]];
arraySpeechSentences = speechSentences;
[speechSentences release];
When I try to call [arraySpeechSentences count] the application crashes. However, if I set the variable in the following way:
// Set the array of sentences to the stored array
NSMutableArray *speechSentences = [[NSMutableArray alloc] initWithArray:[tempDict objectForKey:key]];
self.arraySpeechSentences = speechSentences;
[speechSentences release];
I can call [arraySpeechSentences count] perfectly fine. I was under the impression that if you use self. it simply checks to see if variable is already set, and if so it will release the object before assigning it the new value. Have I got this wrong, and if so when should I be using self. to set values?
Thanks for any help,
Elliott
Using a setter (like self.foo = ... or [self setFoo:...]) does release the old value but it also retains the new value, which is needed in the example you give.
The issue is that you're alloc and init'ing your array, and then releasing it. This indicates you no longer need it. So, you should either use the setter (usually preferable) or don't release your array.
If you're not using ARC, you should type
arraySpeechSentences = [speechSentences retain];
because you're accessing the instance variable directly, which means the value of the instance variable arraySpeechSentences will be the address of the speechSentence object, which you just released, so which is an invalid pointer. The semantic you declared in the property doesn't have an effect on the instance variable itself.
When you type self.arraySpeechSentences, you're actually using a shortcut for the setter [self setArraySpeechSentences:speechSentences], which actually retains the value passed as parameter (if you synthesized the property, it is retained because you specified retain in the property declaration; if you wrote the accessor yourself, it is your job to ensure you retained the value).
I'll try to give a detail answer for this.
First when you use #property/#synthesize directive you create getter and setter methods around a variable.
In your case, the variable is called arraySpeechSentences (the compiler will create the variable for you) and you can access these methods (setters and getters) with self..
self.arraySpeechSentences = // something
is the same as
[self setArraySpeechSentences:something]; // setter
And
NSMutableArray* something = self.arraySpeechSentences;
is equal to
NSMutableArray* something = [self arraySpeechSentences]; // getter
In the first snippet of code
NSMutableArray *speechSentences = [[NSMutableArray alloc] initWithArray:[tempDict objectForKey:key]];
arraySpeechSentences = speechSentences;
arraySpeechSentences points to the same object speechSentences points to. But when you do [speechSentences release] you dealloc that object and now arraySpeechSentences is a dangling pointer. You receive a message sent to a deallocated instance I suppose. Try to enable Zombie to see it.
Speaking in terms of retain count, the array has a retain count of 1 when you do alloc-init.
But when you release it, the retain count goes to zero, the object doesn't exist anymore and you have a crash when you try to access arraySpeechSentences.
Instead, when you deal with properties, the policy applied to a variable is important. Since the property use a retain policy, when you set an object
self.arraySpeechSentences = // something
the retain count for the referenced object is increased. Under the hood, saying self.arraySpeechSentences = // something is equal to call the setter like
- (void)setArraySpeechSentences:(NSMutableArray*)newValue
{
// pseudo code here...
if(newValue != arraySpeechSentences) {
[arraySpeechSentences release];
arraySpeechSentences = [newValue retain];
}
}
The second snippet work since the retain count for your object is one when you do alloc-init, becomes two when you call self.arraySpeechSentences = and returns to one when you do the release. This time, the object is maintained alive since it has a retain count of 1.
If you have a property with a retain or copy policy, don't forget to release the object in dealloc like, otherwise you can have leaks.
- (void)dealloc
{
[arraySpeechSentences release];
[super dealloc];
}
To understand how Memory works I suggest to read MemoryManagement Apple doc.
P.S. Starting from iOS 5 there is a new compiler feature, called ARC (Automatic Reference Counting), that allows you to forget about retain/release calls. In addition, since it forces you to think in terms of object graphs, I suggest you to take a look into.
Hope that helps.

how to clear an NSMutableArray of custom objects without creating memory leaks?

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!

UITableView crashes array problem help

i have an UITableView and im trying to return the number of rows using [arrayName count] however when i run the application it seems to be crashing with no errors showing in console. Here is some code .. (also when i test the array in ViewDidLoad using NSLog, it does return '16' so im not sure why it crashes when i do the row count. Thanks ..
I think the problem is in this line:
elements = [xpathParser search:#"//div[starts-with(#id,'content_div')]//a"];
I guess the - search method returns an autoreleased object, so that your elements object receives the release message after the method viewDidLoad returns and hence gets deallocated.
You can fix this in two ways:
add a retain call, like this
elements = [[xpathParser search:#"//div[starts-with(#id,'content_div')]//a"] retain];
use properties, like this
self.elements = [xpathParser search:#"//div[starts-with(#id,'content_div')]//a"];
You don't need to release htmldata as it is already autoreleased. Remove the [htmldata release]; line and it should work.
Also, you don't, ever, release an object after the [super dealloc] line. Bring the line [elements release]; before the super dealloc.
You don't do a retain on elements, and when you assign it, you assign it directly to the property, and don't go through the setter.
Try:
self.elements = [xpathParser search:#"//div[starts-with(#id,'content_div')]//a"];
Also, don't forget to release it in the dealloc method.

Memory management in objective-c

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/

NSMutableArray gets corrupted

I'm doing an iPhone application which uses a navigation control to browse through some data. This data is stored in a sqlite database and I have a class which gets it and returns it in a NSMutableArray of NSStrings.
The problem is that in the first screen of the navigation everything works prefectly, but in the second screen (another view which is pushed) the same code fails because the NSMutableArray gets corrupted. In the debugger I can see that it is returned correctly, but when it's time to use it the pointers have become corrupted and the application crashes.
I have put breakpoints in all my functions, and I can't see anywhere where it can get corrupted. And as the first view, which uses the same exact code, even accesing the same eact tables, works correctly I don't really know where to look.
If anyone want to have a look at the code I have uploaded it to my site: http://sachafuentes.com/iBacus.zip
Thanks in advance.
UPDATE:
The problem lies in the function where I get the data, which looks like (this is a simplified version with some pseudo-code).
-(NSMutableArray *) getPaises {
NSMutableArray * paises;
paises = [[NSMutableArray alloc] init];
while( get new row ) {
NSString *aPais = get the value;
[paises addObject:aPais];
[aPais release];
}
return paises;
}
If I comment out [aPais release] everything works, but to me this looks like a memory leak, as the NSString won't be released.
Okay, here's the problem:
NSString *aPais = [NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement, 0)];
By convention, any time that you see an alloc and an init, you need a release somewhere down the road.
By convention, any time that you use an xWithX: style method, the resulting object will be released for you.
Therefore, this statement:
[aPais release];
will cause your method to crash, as the object is released before it should be. Just remove this line, set your NSMutableArray instance to be autorelease-d and you should get better results.
Look for wrong memory management, that's the likeliest cause for crashes. I think you release your objects somewhere where you shouldn't and therefore you have dangling pointers in the array.
Update1
[aPais release] is wrong, as you don't retain it anywhere in this method. Returned values should always be autoreleased. You should have the same amount of retain as release in your code.
(Some people argue that a retain can also be an alloc init, but I always try to use alloc init autorelease, but this is a matter of style.)
BTW
You should autorelease your array, you're only retaining it here with [[alloc] init].
Any object that you alloc and init must be release-d when you're finished with it, or you will have a memory leak.
Since you are passing the reference outside the scope of the getPaises method, you must autorelease the NSMutableArray, or you will have a memory leak:
paises = [[[NSMutableArray alloc] init] autorelease];
Can you please clarify the step here:
NSString *aPais = get the value;
It's not clear what happens in "get the value" and I suspect this is one cause of instability.
I see that the code is (verbatim)
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSString *aPais = [NSString stringWithUTF8String:
(char*)sqlite3_column_text(compiledStatement, 0)];
[paises addObject:aPais];
[aPais release];
}
...and it's exactly as #gs puts it. aPais is autoreleased and should not be released.
You can also use a convenience constructor to initialize the NSMutableArray:
NSMutableArray *paises = [NSMutableArray array];
This is equivalent to doing:
NSMutableArray *paises = [[[NSMutableArray alloc] init] autorelease];