Array count throwing exception - iphone

* -[__NSArrayM count]: message sent to deallocated instance 0x5edd5e0
I am Getting this type of exception and its crashing my app. The code is:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(section == 0){
return ([billDetials count]+ 1);
}
int rows = ([billers count] + 1);
return rows;
}
[billers count] for this statement i am getting that exception...
Here billers is NSMutableArray having 6 objects. tableView consists of 2 sections.
so I should get the array count as 6 but its not happenning....

It sounds like the billers array isn't getting retained properly. Make sure it's either a retained property, or that you're retaining it properly when you create that array.
Read and fully understand this:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html%23//apple_ref/doc/uid/10000011i

It appears that the 'billers' NSArray is being deallocated before you call the count method on it. This could be due to autorelease or a manual release before you send the count method.
If you are initializing billers using "alloc" and "init" then you are likely releasing the object too soon. If you are initializing it using a convenience method or with "autorelease", then the object is being garbage collected too soon (you need to retain it).

Related

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.

NSMutableArray memory leaks in recursive method

I have a recursive method that allocates an NSMutableArray, runs a recursive call and then releases the NSMutableArray. the method takes an array of numbers and a target value and then finds what combinations of the numbers can sum up to equal the target value e.g. target: 10, numbers: 5,5,4. the method returns an array of NSNumbers 5 and 5.
My problem is that a mutable array is always showing as a leak in the leaks instrument even though i am releasing it.
here is the recursive method:
-(NSMutableArray *) getCombsHelper:(NSArray *)numbers target:(int)target partial:(NSMutableArray *)partial {
int s = 0;
for (NSNumber *number in partial) {
s += [number intValue];
}
if (s == target)
[results addObject:partial];
if (s >= target)
return results;
for (int i = 0; i < [numbers count]; i++) {
NSMutableArray *remaining = [[[NSMutableArray alloc] init] autorelease];
int n = [[numbers objectAtIndex:i] intValue];
for (int j = i+1; j<[numbers count]; j++) {
[remaining addObject:[numbers objectAtIndex:j]];
}
//this is the array that is showing up as a leak.
NSMutableArray *partialRec = [[NSMutableArray alloc] initWithArray:partial];
[partialRec addObject:[NSNumber numberWithInt:n]];
[self getCombsHelper:remaining target:target partial:partialRec];
[partialRec release]; //the mutable array is released after the recursive call.
}
return results;
}
even if i autorelease it i am still getting it as a leak. Could this be a false positive leak? or is there something wrong i cant catch?
That method is odd;
results appears to be an instance variable that accumulate the results? That is generally odd; typically, you'll have something that calculates state into an ivar and a plain accessor that retrieves the ivar.
To expand: your recursive method is relatively expensive compared to a straight getter method. Say you need results in three places; if this recursive method is the only way to retrieve results, every call will incur calculation overhead. If, instead, you had something like:
- (void)combsHelper:...
- (NSArray*) results
{
return results;
}
Then you could do the calculation once and retrieve the results many times without incurring overhead (while you could do something like if (!results) [self combsHelper:...] in your getter, that'll lead to the getter causing mutation of state which is generally to be avoided -- best to separate the two).
don't name methods getSomething:...; get as a prefix is limited to a very specific use pattern (generally, pass by reference retrieval of a value -- uncommon)..
What array is leaking? Keep in mind that Instruments shows you the point of allocation of the leak, not where the real leak happens. If something is retaining the object elsewhere without a balanced release, that'll be your leak.
The leak is outside of this method; partialRec is being added to the results array. Something is probably retrieving it from said array, retaining it, and not balancing that with a release
Perhaps the complaint is that you pass partialRec to the method, then add it to an array (results), which you return, but you don't catch your return value.
Adding it to the array will retain it.
Where does 'results' come from anyway? I don't see its declaration.
You probably have a problem on this line:
[self getCombsHelper:remaining target:target partial:partialRec];
You are passing partialRec to another method, and it is not autoreleased.

out of bounds error repopulating array for objective c app (iPhone)

I am currently troubleshooting code written by another colleague that has an out of bounds error with the following code. it involves selecting an item in a UINavigatorController. It also involves use of coreData.
the code looks like this (some of the code had been remove for troubleshooting purposes and clarity)
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// : so far no errors with these lines of code. indexPath returns [0,0] or [0,1];
NSLog(#" : *** DetailViewController/didSelectRowAtIndexPath() - executing method ...");
NSLog(#" : *** DetailViewController/didSelectRowAtIndexPath() - indexPath = %#",indexPath);
// : returns row number (as an integer)
NSLog(#": *** DetailViewController/didSelectRowAtIndexPath() indexPath.row = %d",indexPath.row);
// : managedObject returns coreData information.
// Directory *managedObject = (Directory *)[finalArray objectAtIndex:indexPath.row];
// NSLog(#": *** DetailViewController/didSelectRowAtIndexPath() managedObject = %#",managedObject);
// example return
/*
<Directory: 0x5919e50> (entity: Directory; id: 0x59195d0 <x-coredata://FE8A3A0C-A0E4-4E0E-A90D-8471227D2284/Directory/p3> ; data: {
ID = 48;
IsFile = 0;
LastChanged = "2011-01-04 14:39:00 +0000";
Name = "All Papers by Author";
ParentID = 7;
Type = pdf;
}
*/
// : returns the ID value from the managed object
self.num = [managedObject ID];
NSLog(#": *** DetailViewController/didSelectRowAtIndexPath() self.num (managedObject.ID) = %#",[managedObject ID]);
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithArray:finalArray];
// : finalArray has two elements when this method runs
NSLog(#"eja: DetailViewController/didSelectRowAtIndexPath() finalArray length is %i",[finalArray count]);
[self.finalArray removeAllObjects]; // releases the objects, but makes the array empty;
// : finalArray after remove all objects runs
NSLog(#"eja: DetailViewController/didSelectRowAtIndexPath() finalArray length is %i",[finalArray count]);
// ** THE OUT OF BOUNDS ERROR OCCURS HERE **
[self.finalArray setArray:[self searchDatabase:[self.num intValue] withPredicate:#"ParentID"]];**
// NSLog(#": DetailViewController/didSelectRowAtIndexPath() finalArray is %#",self.finalArray);
// ... more code here, but not relevant.
// : release the temp NSMutable array
[tempArray release];
// : maybe release the finalArray?
}
When I debug the app, I believe finalArray is supposed to be cleared (removeAllObjects) and is supposed to be re-populated, but I get an out of bounds error
Terminating app due to uncaught exception 'NSRangeException', reason: '* -[NSMutableArray objectAtIndex:]: index 1 beyond bounds for empty array'
Not sure where the error is coming from, so looking for some advice and tips...
EDIT: i added a new trace statement after the removeAllObjects statement
// : finalArray after remove all objects runs
NSLog(#"eja: DetailViewController/didSelectRowAtIndexPath() finalArray length is %i",[finalArray count]);
it returns a count of 0. So should I suspect then that because it has zero length it has no room to reallocate memory to add new items? I thought that was how Mutable arrays work (more or less).
EDIT 2: Instead of setArray, I also tried add ObjectsFromArray, replacing this:
[self.finalArray setArray:[self searchDatabase:[self.num intValue] withPredicate:#"ParentID"]];**
// with this
[self.finalArray addObjectsFromArray:[self searchDatabase:[self.num intValue] withPredicate:#"ParentID"]];
but I had a similar error returned (out of bounds)...
The -setArray: replaces the existing elements with the elements from the array you are passing in. Thus the -removeAllObjects is redundant, but this is not the cause of your problem.
The size of the array you send -setArray: to is completely irrelevant so the problem probably lies in the array you are getting the elements from i.e. the one you get from:
[self searchDatabase:[self.num intValue] withPredicate:#"ParentID"]
I would separate that out by assigning a temp variable and then examine it in the debugger before the -setArray: and after the -setArray: (set the option "break on OBjective-C exceptions").
I determined the answer to the issue (and it's kind of silly)... I should give some context to the code I wrote above.
The purpose of the code was to use a UINavigationController to display information about directories and files. The problem was in the logic of the code. finalArray was a list of what needed to be displayed (i.e. a list of directories or files) and tempArray held the current directory.
All I needed some additional code to address the length...
// the following code was placed BELOW the code listing in the original question
if ([finalArray] count == 0){
// other code here
finalArray = tempArray; // reassign the current value (a list of files in this case) back to the current array...
} else {
// we will assign finalArray with the value of TempArray first, as "we are not done recursing through"
finalArray = tempArray;
// other code here
}
The out of bounds error showed up as a result of navigating through to a child view in UINavigationController and hitting the "back" button. since the display was not updated with the new menu items (whether it be files or folder listings) "finalArray" was constantly out of whack with what was actually being displayed (hence out of bounds - there may be 2 entries but maybe finalArray referenced one entry, whether it was a file or folder).
Hope this makes sense and thanks to all who looked at this question...
regards
Edward

Zombie Messaged In For Loop

I have an ivar, keys which is an NSMutableArray containing 50 strings. When my view loads, i am getting a zombie messaged error in Instruments, and it is directing me to this line of code:
for (int row = 0; row < r; row++) {
for (int column = 0; column < c; column++){
otherArray[column][row] = [[[keys objectAtIndex:0] retain] autorelease];
//^ Instruments brings me here
[keys removeObjectAtIndex:0];
}
}
I have retained the value to keep it alive so that the remove will not cause a crash, but it still does. I have tried not retaining, and autoreleasing and it still crashes. This method of retaining and autoreleasing works when i have a local variable, but not an ivar...
I need an ivar because i need to access the strings elsewhere.
Thanks
synthesize it and release and it in your dealloc.
Solved -- Memory management problem - keys was not being correctly retained.