views:

373

answers:

3

I have a list of shops in a ListController file. I've setted up a sqlite db, in which i've stored 60 shops. On the top of the list i have a search bar.

I've made a class called DataController, that is responsible to load and store db datas.

@interface DataController : NSObject {
 sqlite3 *database;
 NSArray *shops;    
 NSDictionary* dictionaryOfShops;
}

@property (nonatomic, retain) NSDictionary *dictionaryOfShops;
@property (nonatomic, retain) NSArray* shops;
-(void)initializeShops;

initializeShops method loads data from the db, and stores results into the 2 props in this way:

-(void)initializeShops{
    [dictionaryOfShops release];
    [shops release];

    NSMutableDictionary *dictionary = [[[NSMutableDictionary alloc] init] autorelease];

    if (sqlite3_open(....))
    NSString *query = ....
    if (sqlite3_prepare_v2(database, [query UTF8String],-1, &statement, nil) ==   SQLITE_OK) 
    {
        while (sqlite3_step(statement) == SQLITE_ROW) {

           int rId = sqlite3_column_int(statement, 0);
           char *rName = (char *)sqlite3_column_text(statement, 1);

           Shop* s  = [[Shop alloc] init];
           s.ID = rId;
           if(sName != nil) s.Name = [NSString stringWithUTF8String:rName];

               NSString *shopID = [[NSString alloc] initWithFormat:@"%d",s.ID];
           [dictionary setObject:s forKey:shopID];
           [shopID release];
           [s release];         
        }
        sqlite3_finalize(statement);
    }
    [query release];

    dictionaryOfShops = [[NSDictionary alloc] initWithDictionary:dictionary];
    shops =    [[NSArray alloc] initWithArray:[dictionary allValues]];

    dictionary = nil;
    [dictionary release];

       //Sorting
       NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"Name" ascending:YES];
    NSArray *sortedList =[self.shops sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]];
    self.shops = sortedList; 
    [sort release];
}

The problem is that when user enters some text into the search bar, I change the value of the query (adding LIKE....) and then call the initializeShops method again. This second time makes so many leaks, (related to the Shop class properties) and leaks also a NSDictionary and a NSArray.

Before posting this to you I've tried different solutions, but at least this doesn't leaks anything the first time I call initilizeShops.

I accept any suggestion, since I'm really stuck on it.

MORE:

The really strange thing is memory management of my var dictionary and the 2 props shops and dictionaryOfShops. With this code

NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
//add data to dictionary 
dictionaryOfShops = [[NSDictionary alloc] initWithDictionary:dictionary];
shops =    [[NSArray alloc] initWithArray:[dictionary allValues]];
[dictionary release]

Considering that dictionaryOfShops and shops are two properties (nonatomic,retain) synthesized, how can I change value to them without leaks?

The very first time I pass through this method nothing gets leaked, from the second time it starts to leak so many objects (the contents of the collections).

+1  A: 
dictionary = nil;
[dictionary release];

Please swap these 2 statements. In this form it means [nil release] which is a no-op.

KennyTM
Nope -- do that and it'll just crash since dictionary was autoreleased on creation.
bbum
Oops, sorry. Did not see the `autorelease`. But if you're going to `autorelease` it, you don't need another `release`.
KennyTM
This is exactly the strange part of it. I've updated my question.
sosergio
+1  A: 

The first question is Why not just use Core Data? It is very likely going to be faster, will require less code, and will be significantly easier to maintain over time. To be blunt; SQLite is deceptively hard. Easy to get started, exceptionally difficult to get right.

In any case, the memory management of dictionary is wrong. It only isn't crashing because you swapped the order of the nil assignment and release as kennyTM suggested. I would suggest not creating an autoreleased dictionary.

Otherwise, the code as written seems pretty leakless at first glance. So:

  1. Can you provide some more code? Anything interesting memory wise going on elsewhere?

  2. Are you using threading at all (or NSOperationQueue)?

  3. Have you run under the Leaks instrument and retrieved the backtraces of allocation of the specific objects being leaked?

bbum
CoreData seems to much for my needs; infact I only read data, never write or update. The only thread-like thing i use is the CLLocationManagerDelegate protocol. I've updated my question with some more hints. Thank you.
sosergio
A: 

Ok, I've found the error. In my class Shop, i realize i didn't implement the method

 -(void)dealloc

So when I release the old dictionary (to prepare for a new assignment), all the fields inside of it didn't get released.

sosergio
If you created the string with [NSString stringWithUtf8String:] you got an autoreleased instance which you don't have to release yourself.
weichsel
thank you @weichsel, I changed the answer (I've pasted another text...sorry)
sosergio