当它不应该发生时双重释放

时间:2009-06-29 22:34:01

标签: objective-c memory-management

我对此感到很困惑。我相信我正在以正确的方式管理内存,但执行代码表明我正在双重释放该对象。这是代码,然后我将解释发生了什么。

@protocol SomeDelegate <NSObject>
@required
- (id)initWithCols:(NSUInteger)Cols Rows:(NSUInteger)Rows;
@end


@interface SomeObject : NSObject <SomeDelegate> {
}
- (id)initWithCols:(NSUInteger)Cols Rows:(NSUInteger)Rows;
@end


@interface Layout : UIView {
  id<SomeDelegate> someDelegate;
}
@property(retain) id<SomeDelegate> someDelegate;
- (id)initWithFrame:(CGRect)aRect Cols:(NSUInteger)Cols Rows:(NSUInteger)Rows;
@end


@implementation Layout
@synthesize someDelegate;
- (id)initWithFrame:(CGRect)aRect Cols:(NSUInteger)Cols Rows:(NSUInteger)Rows {

  if(self = [super initWithFrame:aRect]) {
    cols = Cols; 
    rows = Rows;
    id<SomeDelegate> delegate = [[SomeObject alloc] initWithCols:cols Rows:rows];
    [self setSomeDelegate:delegate];
    //[delegate release];
  }
  return self;
}

-(void)dealloc {
    [someDelegate release];
    [super dealloc];
}

@end

现在当我取消注释“// [委托发布];”在Layout类的构造函数中的行,然后我得到一个“EXC_BAD_ACCESS”错误,并且当它尝试dealloc时应用程序崩溃。我已经跟踪了在Layout类的dealloc方法中释放someDelegate对象的崩溃。如果我留下评论,那么应用程序工作正常。

有人可以解释一下为什么会发生这种情况,因为它似乎与我在Objective-C中读到的有关内存管理的内容相违背。

请注意代码示例实际上是有效的,但是我的代码不遵循示例。我的实际SomeObject内部是否会出现导致自动释放的内容?

提前致谢。

3 个答案:

答案 0 :(得分:3)

首先,请返回并重新阅读memory management rules,以确保您在其他地方使用代理时不会遗漏任何明显的内容。

接下来,打开NSZombieEnabled(在可执行设置的Arguments面板中,添加一个环境变量NSZombieEnabled设置为YES)。

然后在你的delagate中添加一个dealloc方法,如果它还没有(请确保你调用[super dealloc]!)并在那里放置一个断点 - 这将告诉你何时你的delagate被解除分配会告诉你当它被释放时。

或者,将普通的释放/自动释放方法添加到您的委托类中,除了调用之外什么都不做,然后断点它们,这将告诉您何时释放它。

三个最终评论:在Objective C / Cocoa的标准命名约定中,你应该有小写参数字段,即它应该是:

- (id)initWithFrame:(CGRect)aRect cols:(NSUInteger)Cols rows:(NSUInteger)Rows;

当您的ivar和属性名称相同时,很容易意外使用错误的名称,因此我建议使用不同的ivar名称和属性名称以避免混淆,使用像Apple这样的_前缀或其他一些前缀为了避免与Apple混淆:

  id<SomeDelegate> _someDelegate;

@synthesize someDelegate = _someDelegate;

Apple建议不要在init / dealloc中使用setter / getter,所以你的init代码应该是:

_someDelegate = [[SomeObject alloc] initWithCols:cols Rows:rows];

答案 1 :(得分:2)

正如评论中所提到的,问题似乎没有出现在发布的代码中。

我可以要求提供更多信息,但我坚定地教导一个人去钓鱼营地......

崩溃 - 释放通常会产生误导,因为各种优化 - 通常是尾部调用优化 - 会使崩溃发生在实际调用崩溃之前的一两帧。当崩溃发生时,堆栈上没有足够的信息来确定罪魁祸首。

每当你怀疑-release或-dealloc中有任何类型的崩溃时,请立即打开Zombies。这可以通过Instruments或环境变量完成,也可以在程序执行的早期调用Foundation中的函数。

在开发环境附带的文档中搜索“Zombies”或“NSZombie”(更像是“教人钓鱼”的事情)。

答案 2 :(得分:0)

问题是一个MutableArray深入一个通过工厂创建的子类(自动释放),但我也发布了。不幸的是,崩溃不会指示哪个继承的dealloc导致崩溃,只是停止在第一个被覆盖的dealloc上。

Zombie的事情有点帮助,因为它告诉我阵列是罪魁祸首,但没有多少。我认为NSZombie还有更多需要更多经验来充分利用它。