自定义SQLite包装器中的内存泄漏

时间:2011-12-12 07:39:05

标签: iphone objective-c memory-management memory-leaks nsdictionary

在我的应用程序中,我连接到sqlite3数据库。我创建了一个包装类,在这个包装类中我有一个NSMutableDictionary和NSMutableArray。

每次运行查询时,来自dictonary的removeAllObjects和说唱歌手类中的数组(我不会释放它)。然后我将查询的结果添加到数组和字典中。该词典包含另一个子词。

我有一个tableViewController,在这个类中我使用我的rapper类从数据库中获取数据并将其复制到我的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 个答案:

答案 0 :(得分:1)

请阅读objective-C memory management guidelines。总之,您必须平衡所有保留操作(retainnewinitcopy)和发布。

由于您正在清空并重新填充结果字典和数组而不是创建新结果字典和数组,然后复制结果,您将保留此对象而不释放它。如果你不止一次这样做,那么你将失去对前一个值的引用,所以你现在有一个内存泄漏。

您需要在分配新值之前释放先前的值,或者更好地创建保留属性并通过合成访问器添加新值。

答案 1 :(得分:0)

[super dealloc];应该是-dealloc方法中的最后一行。在上面的代码中,您将它放在第一位。

这可能会导致意外行为,例如未正确释放您在该点之后执行的对象,包括brandsRecords。当BrandViewController被释放时,这可能会导致泄漏,因为它的实例变量可能永远不会被释放。

另外,正如我对jrturton的答案所评论的那样,不要这样做:

if(brandsIDs)
        [brandsIDs release];

这是一个无用的条件,因为如果brandsIDs已经被释放,默认情况下它不会是nil(除非你使用弱指针,你不在这里),你的应用程序将在此时崩溃。如果它是nil,发送一个nil的版本将不会做任何事情,那么为什么要在那里打扰if语句呢?只需使用[brandsIDs release];

即可