UITableView crashes array problem help - iphone

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.

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.

Objective-C iPhone - NSMutableArray addobject becomes immediately out of scope

ok. I have a really odd and mind boggling problem. I have two class files, both of which are NSObject inheritors. The series of code is as follows
CustomClass *obj;
obj = [[CustomClass alloc] init];
[myArray addObject:obj]; <--------Immediately after this line if I hover over the array it shows it as having 1 object that is out of scope.
If I hover over both objects they both have what look to be initialized memory locations so I really have no idea what is going on here. Thanks in advance.
UPDATE: There is a place in the code where I call a function repeatedly with a timer. Inside of the timer I do the following.
CustomClass *obj = [CustomClass alloc];
obj = [myArray objectAtIndex:0];
obj.var += 10;
[obj release];
On the line obj.var I get a EXC_BAD_ACCESS error. I am probably doing the alloc and releases incorrectly considering it is called repeatedly but I have tried everything I can think of.
I think you are referring to the XCode debugging feature which shows you the content of variables.
I did encounter the same issue as well, and what I'm sure of is that this is generally not a problem with your code.
Now what I'm not sure of is why this happens, but I believe that the variable obj in your example is not used after the call anymore. This means the compiler reuses the place where this reference was stored, thus the debugger could "lose" the pointer to your variable and it will appear as out of scope (but I am no expert in the ways of gcc or the debugger, so I could be wrong here).
This code is wrong:
CustomClass *obj = [CustomClass alloc];
obj = [myArray objectAtIndex:0];
obj.var += 10; [obj release];
What you are doing is allocing a new CustomClass (without initializing it, which should never be done), then replacing it with the object from the array (leaking the old one), and then afterwards releasing the object from the array. This will cause a crash the next time the object in the array is accessed. Instead, just say:
CustomClass *obj = [myArray objectAtIndex:0];
obj.var += 10;
Don't release unless you retain in advance. (See the Cocoa memory management guide for more information).
This isn't the problem you are referring to, but please don't do this:
CustomClass *obj = [CustomClass alloc];
Never issue an alloc without an init of some sort. Also, in the context of the code you posted it isn't required, as you assign a value to obj on the next line.
Then [obj release]; isn't required, as you haven't retained the obj value you obtain from myArray. You are probably doing it because of the preceding alloc, which as I have said isn't required.
if a reference to obj.var is causing a BAD_ACCESS, then either obj or var has been dealloced by code elsewhere, almost certainly var.

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

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.

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];