views:

83

answers:

3

Hi, My controller get data from function in delegat:

 - (NSArray *)getChapters {
 NSMutableArray *list = [[NSMutableArray alloc] init]; //memory leak
  if (chapter_statement == nil) {
        const char *sql = "SELECT DISTINCT 'Глава '||chapter FROM verses WHERE book=? ORDER by chapter";
        if (sqlite3_prepare_v2(database, sql, -1, &chapter_statement, NULL) != SQLITE_OK) {
            NSAssert1(0, @"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
        }
    }

 sqlite3_bind_int(chapter_statement, 1, self.book);
 while (sqlite3_step(chapter_statement) == SQLITE_ROW) {                
  NSString *body = [NSString stringWithUTF8String:(char *)sqlite3_column_text(chapter_statement, 0)];    
  [list addObject:body];
  [body release];
 }

 sqlite3_reset(chapter_statement);
 return list;
}

and use it in controller:

 - (void)viewWillAppear:(BOOL)animated {
 AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

 self.listChapters = [[NSArray alloc] initWithArray:[appDelegate getChapters]];

 [self.listChapters release];

}

Leaks shows a memory leak at : NSMutableArray *list = [[NSMutableArray alloc] init]; If I do return like return [list autorealise]; app crashes in viewWillAppear. How to fix this problem?

A: 

Lets count!

1.) You allocate the leaking array here:

 NSMutableArray *list = [[NSMutableArray alloc] init];

retainCount = 1.

2.) You add the array to another array here:

 self.listChapters = [[NSArray alloc] initWithArray:[appDelegate getChapters]];

What the new array (listChapters) does is retaining your leaking array.

retainCount = 2.

3.) You release the array (listChapters) that contains the leaking array:

[self.listChapters release];

What listChapters does here is also releasing all containing objects once, including your leaking array. Also, all references to your leaking array are lost after this line.

retainCount = 1

thatsdisgusting
The retain count might or might not absolutely be 1 or 2. Never consider the absolute retain count, always consider the deltas.... i.e. alloc is +1, self.listChapters = is +1, -release is -1.
bbum
+1  A: 

You should autorelease in getChapters and you should not release self.listChapters in viewWillAppear. It's just about never a good idea to write [self.something release], because then you're potentially deallocating an object that you still have assigned to that property.

I strongly recommend you read the memory management rules. They're not lengthy or difficult, and once you read through and understand them, you will never even have to think about something like this again.

Chuck
+2  A: 

Returning [list autorelease] is the right thing to do. Your problem is the [body release] which you don't need. The -[NSString stringWithUTF8String:] returns an autoreleased NSString. The explicit [body release] means the list has pointers to deallocated objects.

Delete the [body release] line and put back the return [list autorelease] and it should work.

You can also run the static analyzer (Cmd-shift-A) to ask the compiler to find other memory management issues like this one.

John Franklin
Yes, it's works, but now Leaks shows leak in-[NSPlaceholderString initWithBytes:length:encoding:] in Foundation
V.Vladimir
I suspect that leak is coming from somewhere else. If you haven't already, check out FMDB (http://gusmueller.com/blog/archives/2008/06/new_home_for_fmdb.html) It is a basic Cocoa wrapper for Sqlite that could save you a lot of grief managing DB calls.
John Franklin