【问题标题】:Objective-C - Test for object instance being dealloced/freedObjective-C - 测试对象实例被释放/释放
【发布时间】:2009-06-11 20:06:10
【问题描述】:

有一些方法可以测试objective-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
}
}

谢谢!!

【问题讨论】:

标签: objective-c cocoa cocoa-touch


【解决方案1】:

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

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

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

【讨论】:

  • 哇,正是我今天需要的。谢谢!
【解决方案2】:

你不能测试一个对象是否已经被释放,因为很明显,这个对象已经不存在了。但是,如果您在释放 b 时将其设置为 nil(例如,通过执行 self.b = nil),则可以测试 nil 并创建对象。

【讨论】:

  • 这就是问题所在,我没有显式释放对象,它是由框架类释放的,而且这不会发生在可预测的时间(例如 didReceiveMemoryWarning:方法调用),所以我需要测试我的引用(指针)仍然指向一个有效的实例,如果不是,则分配并初始化一个新实例。
  • 哪个框架类在释放这个类的实例变量?为什么这个类不拥有自己的 ivar?我认为您可能需要在问题中提供更多信息。正如亚历克斯所说,你的属性不应该神秘消失。
【解决方案3】:

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

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

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

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

【讨论】:

  • 标签上写着 Cocoa Touch,所以他不在 Leopard 上。
  • 其中一个标签也是“Cocoa”,而且问题没有指定 iPhone,所以我认为最好是笼统的,并用“if”限定,以帮助那些可能在豹子。
【解决方案4】:

如果你正确地保留 b,它不会在内存不足的情况下被释放。

也就是说,除非您自己解除分配,在这种情况下,您必须在这样做之前手动删除对它的任何引用(通过将其替换为 nil)

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

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

如果您的对象似乎被自动释放,那么您需要检查您的代码以检查您是否已充分保留它。

【讨论】:

    【解决方案5】:

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

    【讨论】:

    • 这不适用于代码中的测试以查看对象是否已被释放。充其量,这将有助于调试与 B 相关的保留释放代码(可能)正确。
    【解决方案6】:

    “try-catch”会起作用吗?

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

    【讨论】:

    • 很确定在释放的实例上调用消息不会抛出正常的异常 bur 而不是 sigbart。
    猜你喜欢
    • 1970-01-01
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-27
    • 1970-01-01
    • 2011-04-17
    • 2011-01-26
    相关资源
    最近更新 更多