views:

162

answers:

2

Hi, I have got I have got two methods both in different classes. One is class method and other is instance method. i am calling class method from instance method. When instance method finishes it gives runtime error "EXC_BAD_ACCESS".

#import "xmlObject.h"
#import "textmeAppDelegate.h"
@implementation Class1 
    - (void)method1 {
               textmeAppDelegate *del = (textmeAppDelegate *)[[UIApplication sharedApplication] delegate];

               NSArray *bgColor = [[NSArray alloc] initWithArray:[xmlObject fetchImmediateChildrenValues:[del.navigationbarStyle objectForKey:@"backgroundcolor"]]];
               UIColor *color = [UIColor colorWithRed:[[bgColor objectAtIndex:3] floatValue] green:[[bgColor objectAtIndex:2] floatValue] blue:[[bgColor objectAtIndex:1] floatValue] alpha:[[bgColor objectAtIndex:0] floatValue]];
               CGContextSetFillColor(context, CGColorGetComponents([color CGColor]));
               CGContextFillRect(context, rect);
               [bgColor release];

        }
    @end

@implementation xmlObject 
        + (NSArray *) fetchImmediateChildrenValues:(NSMutableDictionary *) node {
         NSMutableDictionary *tmp = [[node objectForKey:@"children"] retain];
         NSArray *keys = [[NSArray alloc] initWithArray:[tmp allKeys]];
         keys = [keys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
         NSMutableArray *pushArr = [[[NSMutableArray alloc] init] autorelease];
         NSString *val = [[NSString alloc] init];
         for(NSString *str in keys) {
           val = (NSString *)[[tmp objectForKey:str] objectForKey:@"innertext"];
          [pushArr addObject:val];
         }
         [val release];
         [keys release];

         return  [NSArray arrayWithArray:pushArr];
        }

@end

What is wrong with the code? Also app is crashing for this line of code application is crashing if i include this line

 NSArray *bgColor = [[NSArray alloc] initWithArray:[xmlObject fetchImmediateChildrenValues:[del.navigationbarStyle objectForKey:@"backgroundcolor"]]];

If I remove it application runs smoothly.

+1  A: 

Test your code with NSZombieEnabled set... It should give you enough informations to fix your problem.

Macmade
I enabled NSZombieEnabled. can u tell how can i get reason for "EXC_BAD_ACCESS" runtime error
Ayaz Alavi
EXC_BAD_ACCESS often mean you are sending a message to a deallocated object. NSZombieEnabled will place a dummy object for each deallocated objects, which will inform you when a message is passed after the deallocation.Check your console logs...
Macmade
app crashed on the start with this on console*** -[CFString release]: message sent to deallocated instance 0x43385f0
Ayaz Alavi
+1  A: 

I have several comments on your code. One of them is the immediate cause of your crash, but you need to fix at least one other issue too. The short answer is that you over release val and keys.

NSArray *bgColor = [[NSArray alloc] initWithArray:[xmlObject fetchImmediateChildrenValues:[del.navigationbarStyle objectForKey:@"backgroundcolor"]]];

You don't need to create a new array here, you can simply write the following:

NSArray *bgColor = [xmlObject fetchImmediateChildrenValues:[del.navigationbarStyle objectForKey:@"backgroundcolor"]];

if you do, you don't need the [bgColor release] further down.

NSArray *keys = [[NSArray alloc] initWithArray:[tmp allKeys]];
keys = [keys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];

These two lines leak the first NSArray, you alloc it but you overwrite it straight away with the sorted version. In fact, you can simply write:

keys = [[tmp allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];

Note that you do not own keys so you can get rid of the [keys release] line further down.

NSString *val = [[NSString alloc] init];
for(NSString *str in keys) {
   val = (NSString *)[[tmp objectForKey:str] objectForKey:@"innertext"];
   [pushArr addObject:val];
}
[val release];

This is the source of your immediate problem. You first alloc a new string. Then you immediately overwrite it on each iteration of your loop. So the allocated NSString leaks. You do not own the val returned by [[tmp objectForKey:str] objectForKey:@"innertext"]; on each iteration, so the release ov val after the loop should not be there.

On a side note, objectForKey: returns an id - the cast to NSString* is redundant. Most people leave it out.

         [keys release];

Going back to the bit above where I told you that you were leaking your alloc'd keys? Well the new version of keys you overwrote it with you don't own. Therefore you must not release keys here.

return  [NSArray arrayWithArray:pushArr];

This is fine. My preference would be for:

return [[pushArray copy] autorelease];

but it is just a matter of style. You could also just return pushArray, but pushArray is mutable and the caller may rely on the return value being immutable.

JeremyP
Thanks a million for reply and thanks a trillion for solving issue. It was making me mad. Can u tell me why during app launch I got so many 'malloc: *** error for object 0x43181e0: double free' on console
Ayaz Alavi
Very likely there are a lot of similar issues elsewhere in your code. I think you'll need to review most of it.
JeremyP
I reviewed my app with above points in mind and now there are only few leaks left. What might be the procedure of removing leaks from entire app.
Ayaz Alavi
There is no single procedure as such because the causes of leaks are many and varied. There's a lot of information about the tools you can use here: http://developer.apple.com/iphone/library/documentation/Performance/Conceptual/ManagingMemory/Articles/FindingLeaks.html#//apple_ref/doc/uid/20001883
JeremyP