Objective-C - 测试被解除分配/释放的对象实例

时间:2009-06-11 20:06:10

标签: objective-c cocoa cocoa-touch

有一些方法可以测试一个目标-c实例被解除分配/释放(保留计数== 0)??

例如,对象A有一个对象B的引用(指针),但对象B可以在内存中释放低级别,我如何测试引用B以确定它被解除分配?

@interface A : NSObject {
    B b;
}

@implementation A {

- (void) someAction:(id) sender {
    //is b previously dealloced?? 
    if ..... ???? {
        b = [[B alloc] init];
    }
    // continue
}
}

谢谢!

6 个答案:

答案 0 :(得分:13)

如果设置NSZombieEnabled环境变量,则解除分配的对象将成为NSZombie的实例。它们在下一次消息时抛出,导致代码崩溃和刻录 - 正是您需要调试这种情况。

http://www.cocoadev.com/index.pl?DebuggingAutorelease

更新:对于XCode 4.0,请参阅How to enable NSZombie in Xcode?

答案 1 :(得分:11)

您无法测试对象是否已被解除分配,因为显然该对象不再与之交谈。如果在释放它时将b设置为nil(例如,通过执行self.b = nil),则可以测试nil并创建对象。

答案 2 :(得分:3)

由于变量b完全在类A的内部,并且未声明为@public(默认为@protected),因此了解{{已释放的{1}}是释放它并将指针设置为b。这样,您只需检查nil并在必要时创建新实例。

然而,更大的问题是if (b == nil)的真实本质和记忆行为是什么。您声明“对象B可以在内存中释放低级别”,但不解释原因。如果你在Objective-C中使用标准习惯用于保留释放,我认为A将是确定是否应该释放B的那个,因为它正在创建一个新实例。如果您不打算让A做出这样的决定,那么允许它分配一个新的B将导致所有权混乱和内存错误。

如果A 负责B,如果你在Leopard(或更高版本)启用了垃圾收集,那么您可能想要的是归零弱引用。这是在实例变量声明之前使用b声明的,并不会阻止垃圾收集器收集它指向的对象。 (“强”引用是默认值,垃圾收集器不会释放它只能通过强引用从根跟踪的对象。)此外,如果/当对象是,则GC将自动将弱引用设置为0解除分配。

回到“更大的问题”,除非__weak已经是弱引用并且GC打开(并且其他一些条件成立),系统不会自动为您释放B.如果解除分配b的原因是B的实例随着时间的推移而增长(例如可分配项目的缓存),那么有一种方法可以清空B.例如,Foundation中的可变集合有一个b方法。这种方法可以避免大多数关于-removeAllObjects是否仍然存在的混淆,并且比重复(de)分配对象更有效。

答案 3 :(得分:2)

如果正确保留b,则在内存不足的情况下不会取消分配。

也就是说,除非您自己取消分配,否则在您执行此操作之前手动删除对它的任何引用非常重要(通过将其替换为nil)

在这种情况下,只需测试nil值即可:

  if (nil == b)
  { 
    reallocate b;
  }

如果您的对象似乎正在自动解除分配,那么您需要检查您的代码以检查您是否已充分保留它。

答案 4 :(得分:0)

您可以尝试将NSLog消息放入对象dealloc方法中。这至少会告诉你何时释放对象。

答案 5 :(得分:-3)

会“尝试捕捉”吗?

 @try {
      [b description]; // test it... 
 }
 @catch (NSException * e) {
    NSLog(@"Exception: %@", e);
 }
 @finally {
    NSLog(@"finally");
 }