【问题标题】:Memory leak in custom SQLite wrapper自定义 SQLite 包装器中的内存泄漏
【发布时间】:2012-01-18 06:21:36
【问题描述】:

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

每次运行查询时,我都会从字典和说唱歌手类中的数组中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;
         }

【问题讨论】:

  • 你能把getAllrecordByRecords的代码贴出来吗?
  • 这就是您的真实代码,还是您记忆中的代码?顺便说一句,调用您的实例变量NSArray... 不是一个好习惯。变量名应该以小写字母开头,当然不应该与框架类的命名空间冲突。
  • 很抱歉,因为这是我第一次在表单上发布问题,现在我添加了所有真实的代码,还有一个说唱歌手类...

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


【解决方案1】:

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

由于您是清空并重新填充结果字典和数组,而不是创建一个新的然后复制结果,因此您将保留此对象而不是释放它。如果您多次执行此操作,那么您将丢失对先前值的引用,因此您现在有内存泄漏。

您需要在分配新值之前释放以前的值,或者最好还是创建一个保留属性并通过合成访问器添加新值。

【讨论】:

  • 能否给我详细的解释、代码或链接,谢谢
  • 我刚刚完成了 Objective-C 内存管理指南,但我仍然无法解决这个内存泄漏问题......关于你的答案,我能以某种方式考虑我的应用程序的唯一好处是你说“如果你不止一次这样做”......你能指导我给我一些例子吗,因为当我认为我可以说当它超过一次时,我改变了视图控制器,内存泄漏发生了..
  • @liligago - 作为一个不同的问题,在上面的代码中使用if (brandsRecords) [brandsRecords release]; 是一种不好的做法,并且可能导致崩溃。 brandsRecords 不会在解除分配时自动变为 nil,所以这个条件是没有用的,如果 brandsRecords 已经被解除分配会导致崩溃。
  • 谢谢@BradLarson..我在读内存管理后得到了它
【解决方案2】:

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

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

另外,正如我评论 jrturton 的回答,不要这样做:

if(brandsIDs)
        [brandsIDs release];

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

【讨论】:

  • 我已经应用了这两个问题,但我仍然面临内存泄漏......
猜你喜欢
  • 1970-01-01
  • 2015-02-17
  • 2021-03-30
  • 2017-07-25
  • 1970-01-01
  • 1970-01-01
  • 2018-07-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多