Утечка памяти в пользовательской оболочке SQLite - PullRequest
0 голосов
/ 12 декабря 2011

В моем приложении у меня есть соединение с базой данных sqlite3. Я сделал класс-оболочку, в этом классе-оболочке у меня есть NSMutableDictionary и NSMutableArray.

Каждый раз, когда выполняется запрос I removeAllObjects из диктонары и массива в классе рэпера (я его не освобождаю). Затем я добавляю результаты запроса в массив и словарь. Словарь содержит еще один подсловарь.

У меня есть tableViewController, в этом классе я получаю данные из базы данных, используя мой класс рэпера, и копирую их в мою переменную tableviewcontroller:

.h

     @interface BrandViewController : UIViewController
<UITableViewDataSource , UITableViewDelegate>
{
    FairPriceDatabaseView *FairPriceDB;
    NSArray *brandsIDs;
    NSMutableDictionary *brandsRecords;
    UITableView *tableView;  
}

.m

    - (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self loadBrandsIDs];
    [tableView reloadData];
}
- (void)dealloc {[brandsRecords release];
    [brandsIDs release];
    [super dealloc];
}
-(NSArray *) loadBrandsIDs
{
    [self loadBrandsDB];

    [brandsIDs release];
    brandsIDs = [[FairPriceDB getBrandIDs]copy];

    [brandsRecords release];
    **brandsRecords = [[FairPriceDB getBrandIDs_NSDictionary]copy];**

    [FairPriceDB release];
    FairPriceDB = nil;
    return brandsIDs;
}
- (FairPriceDatabaseView *) loadBrandsDB {
    if (!FairPriceDB) 
        FairPriceDB = [[FairPriceDatabaseView alloc] initWithFairPriceDatabaseViewFilename:@"b.db"];
    return FairPriceDB;
}

При тестировании я получаю утечку памяти в звездной строке (brandsRecords = [[FairPriceDB getBrandIDs_NSDictionary]copy];) происходит утечка памяти, когда я меняю tableviewcontroller и возвращаюсь к этим tableviewcontrollers ....

Я хочу знать, правильно ли я поступаю? Почему есть утечка?

Кроме того, каждый раз, когда я выпускаю NSMutableDictionary, мне также нужно освобождать субдискретарий, который там содержится или нет?

FairPriceDataBaseViewController.h (класс-оболочка)

@interface FairPriceDatabaseView {
    NSMutableArray * idList;
    NSMutableDictionary * recordList;
}

FairPriceDataBaseViewController.m (класс-оболочка)

            - (NSArray *) getBrandIDs {
                NSDictionary * row;
                [idList removeAllObjects];  // reset the array
                for (row in [self getQuery:@"SELECT productID,brandName FROM product GROUP BY brandName;"]) 
                    [idList addObject:[row objectForKey:@"productID"]];
                return idList;
            }

            -(NSDictionary *) getBrandIDs_NSDictionary{
                [recordList removeAllObjects];
                [idList removeAllObjects];
                [self getBrandIDs];

                NSNumber * rowid;
                for(rowid in [self idList])
                    [recordList setObject:[self getProductRow:rowid]  forKey:rowid];

                return recordList; 
            }
        - (NSDictionary *) getProductRow: (NSNumber *) rowid {
            self.tableName = @"select * from product where productID = ?";
            return [self getRow:rowid];
        }
        -(FairPriceDatabaseView *) initWithFairPriceDatabaseViewFilename: (NSString *) fn
         {
             if((self = (FairPriceDatabaseView *) [Super initWithDBFilename:fn]))
             {
                    idList = [[NSMutableArray alloc] init];
                    recordList = [[NSMutableDictionary alloc]init];
             }
              [self setDefaults];
              return self;
         }

Ответы [ 2 ]

1 голос
/ 12 декабря 2011

Прочтите рекомендации по управлению памятью target-C . Таким образом, вы должны сбалансировать все свои операции хранения (retain, new, init, copy) с выпусками.

Поскольку вы очищаете и пополняете свой словарь результатов и массив, а не создаете новый, а затем копируете результаты, вы сохраните этот объект, а не освободите его. Если вы сделаете это более одного раза, вы потеряете ссылку на предыдущее значение, поэтому у вас теперь есть утечка памяти.

Вам необходимо освободить предыдущее значение перед назначением нового или, что еще лучше, создать сохраненное свойство и добавить новое значение через синтезированный метод доступа.

0 голосов
/ 12 декабря 2011

[super dealloc]; должна быть последней строкой в ​​методе -dealloc.В приведенном выше коде вы размещаете его первым.

Это может вызвать непредвиденное поведение, например, неправильное высвобождение объектов, которые вы делаете после этой точки, включая brandsRecords.Это может привести к утечке, когда BrandViewController освобожден, потому что его переменные экземпляра никогда не могут быть освобождены.

Также, как я прокомментировал ответ jrturton, не делайте этого:

Это бесполезное условие, потому что, если brandsIDs был освобожден, по умолчанию он не будет равен нулю (если вы не используете слабые указатели, которых здесь нет), и ваше приложение в этот момент завершится сбоем.Если это ноль, отправка релиза в ноль ничего не сделает, так зачем беспокоиться о наличии там оператора if?Просто используйте [brandsIDs release];

...