【问题标题】:Releasing NSMutableArray in dealloc causes the app to crash在 dealloc 中释放 NSMutableArray 会导致应用崩溃
【发布时间】:2012-10-11 23:11:49
【问题描述】:

我有一个UIView,其中包含一个UITableView。此表由 NSMutableArray 填充。

我在 UIView 的 initWithFrame: 方法中初始化了数组和表格。

- (id)initWithFrame:(CGRect)frame
{
  self = [super initWithFrame:frame];
  if (self)
  {
    bookTable = [[UITableView alloc]initWithFrame:CGRectMake(100, 108, 260, 535)];
    bookArray = [[NSMutableArray alloc]init]; //this array will be populated later

    //other codes
  }
  return self;
}

我在dealloc发布它们:

- (void)dealloc
{
   [bookTable release];      
   [bookArray release];

   [super dealloc];
}

问题是当应用程序在dealloc 中崩溃时。它产生错误:[CALayer release]: message sent to deallocated instance 0x82db660

我在我的代码中到处查看,我确信我没有过度发布任何东西。我决定删除dealloc 中的[bookArray release],它就停止了崩溃。我运行了Analyze,它没有给我任何潜在的泄漏。

谁能解释一下为什么在 dealloc 中释放数组会导致崩溃?

注意: 表和数组都是视图的实例变量。

编辑: 填充数组的代码:

NSString *sql = [NSString stringWithFormat:@"SELECT BookName FROM books WHERE UserID=%d", userId];
booksArray = [sqlite executeQuery:sql];

请注意,我使用的是 sql 包装器。

【问题讨论】:

  • 只要确保您没有为项目启用 ARC。
  • 如果启用了 ARC,编译器将不允许使用 [super dealloc]...
  • 你能提供你用来填充数组的代码吗?
  • @Tobi 我在上面添加了代码。
  • @AnnaFortuna 如何向bookArray 添加元素?

标签: ios memory-management memory-leaks nsmutablearray


【解决方案1】:

我建议像这样为 booksArray 创建一个属性:

@property (nonatomic, retain) NSMutableArray *bookArray;

当您填充它时,请尝试以下代码:

self.bookArray = [NSMutableArray arrayWithArray:[sqlite executeQuery:sql]];

这将创建返回数组的自动释放副本,然后由属性“自动”保留。

当然你应该确保 [sqlite executeQuery:sql] 返回的数组是自动释放的。

【讨论】:

    【解决方案2】:
    1. 更改executeQuery 方法的返回语句,如[array autorelease]
    2. booksArray = [sqlite executeQuery:sql]; 替换为booksArray = [[sqlite executeQuery:sql] retain];

    如果您为booksArray 写了property,例如@property(nonatomic, retain) NSMutableArray *bookArray;,那么您可以将步骤2替换为self.bookArray = [sqlite executeQuery:sql];

    您的问题是您正在从 executeQuery 方法返回一个已发布的对象(您在评论中提到了它)。这就是您收到错误的原因

    【讨论】:

      【解决方案3】:

      我认为问题只是在这里。

      booksArray = [sqlite executeQuery:sql];
      

      executeQuery 方法可能返回一个自动释放的 NSMutableArray 或者类似的东西可能写在 executeQuery

      NSMutableArray* tempArray = [NSMutableArray arrayWithCapacity:0];
      

      如果是这样,它应该已经处于自动释放模式,因此dealloc方法中没有release

      更新

      另外,为数组分配 0sign 属性。

      @property (nonatomic, retain) NSMutableArray* booksArray;
      

      然后,无论您在哪里使用它,都将其用作self.booksArray

      self.booksArray = [sqlite executeQuery:sql];
      

      这样就可以进行适当的内存管理,然后在dealloc中释放数组。

      【讨论】:

      • 嗨。 executeQuery 方法返回:[array release];
      • 改成[array autorelease];
      • 我还有一个问题。如果我调用removeAllObjects,它会减少数组的保留计数吗?
      • 否,但此时会减少数组中对象的保留计数。
      【解决方案4】:

      问题来了

      booksArray = [sqlite executeQuery:sql];
      

      sqlite 返回的数组是一个自动释放的对象。您必须保留它或从 `dealloc' 中删除释放。

      booksArray = [[sqlite executeQuery:sql] retain];
      

      由于它是自动释放的对象,当系统也尝试release它时,在dealloc中释放它会导致崩溃。

      并删除init方法中的数组初始化,这是多余的。

      【讨论】:

      • 我这样做了:booksArray = [[sqliteArray valueForKey:@"Books"]retain];,但它仍然崩溃。
      • 好吧,现在我猜,但删除保留并删除 dealloc 中的 release 调用。这不会是内存泄漏。尝试仪器确认
      • 它泄露了。首先,因为数组是自动释放的。然后像NSFireDelayedPerform 这样的东西也释放了数组。所以当我的表试图访问数组的内容时,它会崩溃。
      • 如果问题仍然存在,请使用gist.github.com共享整个 .m 和 .h 文件
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-07
      • 1970-01-01
      • 2013-01-27
      • 1970-01-01
      • 2011-12-31
      • 2012-02-27
      相关资源
      最近更新 更多