views:

54

answers:

2

I have two problems

1) My App works fine on the device the first few times its run. Then it crashes after the First screen pops up(Tab BAr). If i connect the device to my MAC and then run the device app it works(not debug mode).

I Checked the crash Logs, it crashed cos of "EXC_BAD_ACCESS (SIGSEGV)" and Thread0 crashed.The error was NSAutorelease released a deallocated Object.

2) I ran the app using instruments on the simulator. It show a lot of leaks on this function call. Here is a sample code. When i run it using Instruments it shows a leak on the "setObject" line.

//class A- subclass of NSObject

+(NSMutableDictionary *)Hello {

 NSMutableDictionary *dctONE = [[NSMutableDictionary alloc]initWithCapacity:0];
 NSMutableArray *arrKeys = [[NSMutableArray alloc] initWithCapacity:0];

    [arrKeys addObject:@"Object1"];
 [arrKeys addObject:@"Object2"];

    [dctONE setObject:[NSString stringWithFormat:@"dsfsdf"] forKey:[arrKeys          objectAtIndex:0]];
 [dctONE setObject:[NSString stringWithFormat:@"dsfsdf"] forKey:[arrKeys objectAtIndex:1]];

    [arrKeys release];
    return dctONE;

}

/// class B

-(void)some_Function {
 NSMutableDictionary * dct = [A Hello];   //all declarations are done

 //do stuff with dct
 [dct release];
}

WHy does it Leak at "setObject"?? I am releasing everything properly right? Only thing is the [NSString stringWithFormat:] but that is autorelease right??

This is driving me Crazy?

Are the two problems related?? PS: It Doesnt crash on the sim, and strangely doesnt crash even when i connect my device to my MAC and then test it on device(not debugging, directly clicking the app on the device)

EDIT:

-(NSMutableDictionary *) ExecuteDataSet:(NSString *)strQuery
{
    NSMutableDictionary  *dctResult = [[[NSMutableDictionary alloc] init] autorelease];
//  BOOL isSucess = FALSE;

const char *sql = [strQuery UTF8String];
sqlite3_stmt *selectStatement;

//prepare the select statement
int returnValue = sqlite3_prepare_v2(database, sql, -1, &selectStatement, NULL);
if(returnValue == SQLITE_OK)
{
    sqlite3_bind_text(selectStatement, 1, sql, -1, SQLITE_TRANSIENT);
    //loop all the rows returned by the query.
    NSMutableArray *arrColumns = [[NSMutableArray alloc] init];
    for (int i=0; i<sqlite3_column_count(selectStatement); i++) 
    {
        const char *st = sqlite3_column_name(selectStatement, i);
        [arrColumns addObject:[NSString stringWithCString:st encoding:NSUTF8StringEncoding]];
    }
    int intRow =1;
    while(sqlite3_step(selectStatement) == SQLITE_ROW)
    {
        NSMutableDictionary *dctRow = [[NSMutableDictionary alloc] init];
        for (int i=0; i<sqlite3_column_count(selectStatement); i++)                 
        {
            int intValue = 0;
            const char *strValue;
            switch (sqlite3_column_type(selectStatement,i)) 
            {
                case SQLITE_INTEGER:
                    intValue  = (int)sqlite3_column_int(selectStatement, i);
                    [dctRow setObject:[NSString stringWithFormat:@"%d",intValue] forKey:[arrColumns objectAtIndex:i]];                      
                    break;

                case SQLITE_TEXT:
                    strValue = (const char *)sqlite3_column_text(selectStatement, i);
                    [dctRow setObject:[NSString stringWithCString:strValue encoding:NSUTF8StringEncoding] forKey:[arrColumns objectAtIndex:i]];                     
                    break;

                default:
                    strValue = (const char *)sqlite3_column_value(selectStatement, i);
                    [dctRow setObject:[NSString stringWithCString:strValue encoding:NSUTF8StringEncoding] forKey:[arrColumns objectAtIndex:i]];
                    break;
            }

        }
        [dctResult setObject:[dctRow retain] forKey:[NSString stringWithFormat:@"Table%d",intRow]];
        intRow ++;
        [dctRow release];
    }
    [arrColumns release];
}
return dctResult;

}

+1  A: 

The leak appears to be in this line:

[dctResult setObject:[dctRow retain] forKey:[NSString stringWithFormat:@"Table%d",intRow]];

setObject will call retain on the object it stores, but you are actually retaining it manually, so its retain count will be 2 instead of 1, and when dctResult gets released, it won't be removed from memory.

pgb
Ok, so any idea why "Leaks" says that [dctOne setObject:] is a "retain" and i am not releasing it.
BK
Also if i release it via the "caller" its not wrong right? And also any thoughts on my first Problem. the device crash??
BK
Based on your error, it seems that you are manually calling `release` on an object that is in an autorelease pool, then, when the pool calls `release` it triggers the error. You can try enabling NSZombies to track down the problem, and see what deallocated object is getting the message.
pgb
@pgb Thats the problem, I have gone through the code extensively and i am not releasing any variable thats in the autorelease pool. The only place where i am confused is the "setObject", as i do a [stringWithFormat:] and later release the dictionary, is the error because of this?
BK
@pgb I tried using NSZombies but it came out clean. NO Problems were detected. :(
BK
@pgb Thanks, that did it. Although the crash on device usually starts after a couple of days of installing the app on the device. But i guess this is it. :)
BK
+1  A: 

You're doing a whole bunch of unnecessary work in +Hello. My first step at debugging is always to remove unnecessary complexity. Try it like this:

+(NSMutableDictionary *)Hello {

     NSMutableDictionary *dctONE = [NSMutableDictionary dictionaryWithObjectsAndKeys:
         @"dsfsdf", @"Object1", @"dsfsdf", @"Object2", nil];

     return dctONE;
}

That NSMutableDictionary dictionaryWithObjectsAndKeys method takes a nil-terminated array that goes object, key, object, key. It returns an autoreleased NSMutableDictionary object, which is what you want to be returning.

There are no guarantees in this world, but I can darn near promise you that method won't leak.

Dan Ray
@Dan Thanks for the reply but the Hello function i posted here is not the actual one. The [dctONE setObject:] comes in a while loop which is accessing data from a sqlite DB. Leaks was showing a leak on that line, so i jus posted a simplified version.
BK
@BK: Okay, well, glean what you can from my simplification of your simplification, then. Particularly the use of convenience instantiators that return autoreleased objects.
Dan Ray
@Dan I did as u told and returned a autoreleased Object but still no Luck. "Leaks" is pointing out to [setObject:] as the culprit.
BK
It's hard to diagnose this when I'm not looking at the real code. You're aware that [NSString stringWithFormat:@"abcd"] an unnecessary construct, right?
Dan Ray
ya i am aware of that. I use this to fill up The dictionary with values returned frm the Db -[stringWithFormat:@"%d",a]; Wait will put the actual code.
BK
The `stringWithFormat:` looks ok to me...
pgb
@pgb: in his real code, yes. In the fake code he posted first, he was doing it without any variables to format, which just makes it a waste of typing.
Dan Ray
@Dan it was a unnecessary retain. If not for you i would not have posted the actual code, so thanks
BK