【问题标题】:What is the lifecycle of an object caught in a @catch block?@catch 块中捕获的对象的生命周期是什么?
【发布时间】:2012-01-11 23:37:41
【问题描述】:

当您在 ObjC @catch 块中捕获异常时,该异常对象的生命周期是什么?我知道我可以在块内安全地使用它,但是如果我想在块之后再次使用它怎么办,像这样?

NSException * exception = nil;
@try {
    // do something risky
} @catch(NSException * e) {
    exception = e;
}

if (exception) {
    NSLog(@"Caught exception: %@", exception);
}

我可以安全地将引用存储到另一个本地吗?为了安全起见,我应该retain, autoreleaseing 吗?我可以保留它并无限期地持有它吗?

(如果我分配给本地,或者稍后保留并使用,它似乎工作正常,但是文档并没有真正讨论这个对象在所有权方面“来自”哪里,或者它是否特殊,所以我正在寻找更多的清晰度。)

【问题讨论】:

    标签: objective-c try-catch nsexception


    【解决方案1】:

    http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Exceptions/Tasks/HandlingExceptions.html

    几乎所有 NSException 对象(和其他类型的异常对象)都是自动释放创建的,它将它们分配到最近的(在范围内)自动释放池。当该池被释放时,异常被销毁。

    另外,我很确定在memory programming guide 的某个地方,他们提到名称中没有newalloccopy 的方法总是按约定返回自动释放的对象。 NSException's methods 符合条件。

    稍微相关(不是 NSException 而是 NSError):

    如果你使用 initWithDomain:code:userInfo: 创建一个 NSError 对象,你应该在返回给调用者之前发送 autorelease 给它。

    http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ErrorHandlingCocoa/CreateCustomizeNSError/CreateCustomizeNSError.html

    【讨论】:

    • 很好的参考。该页面上也有关于异常自动释放池行为的更详细讨论,这是我非常感兴趣的一个棘手案例。
    • 仍然不确定“几乎所有”是什么意思。
    • 也许这只是约定俗成的意思。当然[NSException raise... 会自动释放,但你当然可以这样做:id foo = [[Foo alloc] init]; @throw foo;
    • 我奖励你在这里获得最详细的答案。我希望对运行时中的堆栈展开及其含义进行完全权威的讨论,所以我暂时不回答它。谢谢!
    【解决方案2】:

    NSException 采用NSCopying(和NSCoding fwiw)。如果您的生命周期有问题并且想要明确说明,那么副本将是理想的。

    我停在那里 - 放松和可可成语相互矛盾。

    【讨论】:

      【解决方案3】:

      @catch 块对于生命周期绝对什么都不做。这里的隐式契约是一个NSException 对象,-raise'd 或@thrown 应该是一个自动释放的对象。这意味着在@catch 块中,给您的NSException 是一个自动释放对象,就像您可能从方法调用中获得的任何自动释放对象一样。您可以安全地将其存储在本地并在 @catch 块之后引用它。

      【讨论】:

      • 如何(如果有的话)嵌套自动释放池?我在抛出的地方得到了这个,你会抛出一个自动释放的对象,但是如果它最终被多个嵌套的自动释放池抛出怎么办?如果@finally 块中有drains 怎么办?假设运行良好,这个潜在问题是否会被运行时忽略?或者这里的运行时发生了什么特别的事情?
      • @quixoto:如果它通过自动释放池抛出,这些池会掉在地板上并且不会流失。但是,由于自动释放池的工作方式,一旦外部池排水,所有掉落在地板上的内部池也会排水。但是,是的,如果您在 @finally 块内有 drains,那么我不确定异常的行为方式。它可能在被抛出时被系统保留,我真的不知道。
      【解决方案4】:

      NSException 继承自 NSObject,因此您可能可以做所有其他 Objective C 对象会做的典型事情。

      但是,我建议不要在您的线程之外对其进行任何操作。 This O'Reilly article about Exceptions 建议:

      不要使用releaseautorelease 消息来处理 NS异常。 NSException 的所有实例都放在 main 自动释放池。手动处理实例将导致 SIGSEGV 错误。

      不要使用retain 消息来保留 NSException。 它将阻止自动释放池释放实例。这 只会导致细微的内存泄漏。

      ...以及有关这些对象的其他一些有用的有用提示。

      【讨论】:

      • 书中的建议似乎毫无用处。它只是描述正常的内存管理策略。它描述的问题是如果您释放而不保留,或者保留而不释放(或自动释放)。如果你两者都做,我猜应该不是问题。
      • 这里唯一相关的行似乎是“NSException 的所有实例都放置在主自动释放池中。”我希望有一个指向 Apple 文档的指针,它说明了这一点,并且明确说明了这与堆栈从异常中展开的关系。 (例如,它是在它被捕获的时候神奇地放在顶部的自动释放池中吗?或者它被抛出的地方,假设那个池没有被清理)
      • 我很确定这意味着当前的自动释放池
      猜你喜欢
      • 2013-06-11
      • 2014-11-20
      • 1970-01-01
      • 1970-01-01
      • 2020-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多