【问题标题】:What does @throw accomplish@throw 完成了什么
【发布时间】:2013-07-26 03:57:41
【问题描述】:

我了解@try 和@catch 块的作用,但@throw 是做什么的?

@try{

/**Insert code here**/

}

@catch(NSException * myException){

/**insert code **/

}

@throw 适合这一切吗?一个简单的例子会很有帮助。

我查看了此链接,但找不到我正在寻找的答案。

https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Exceptions/Tasks/RaisingExceptions.html

【问题讨论】:

  • 扔东西让你能抓住它
  • 所以为了抓住它, throw 总是在 @try 块内吗?只能抛出异常吗?
  • 您只能抛出异常,但如果您需要更多信息,您可以定义自己的扩展NSException 的类。 try 块定义了一个代码块,您可以在其中预测要抛出的异常。如果 try 块中的任何代码抛出异常,它将被相应的 catch 块捕获。如果某个不在 try 块内的代码抛出异常(或者没有捕获异常的 catch),那么您就有一个“未处理的异常”。
  • 坦率地说:异常应该只用于不可恢复的错误。你不应该尝试在@catch中恢复和继续。
  • OP - 如果您找到了问题的解决方案,请务必将相应的答案标记为正确。

标签: objective-c


【解决方案1】:

Objective-C 中的异常主要用于明显的程序员错误情况,例如试图访问NSArray 范围之外的元素。相比之下,一些编程语言使用异常来指定任何类型的可恢复错误,例如“找不到文件”,但在 Objective-C 和 Cocoa 中,与@throw 一起抛出的NSException 通常意味着没有什么可以做好恢复。

在任何一种情况下,类比都是异常被“抛出”给捕获器,无论在抛出器和捕获器之间有多少函数调用。这与通过返回值或输出参数返回错误状态的函数形成对比。返回错误状态的函数需要确保链中的所有其他函数都返回相同的错误状态,以便另一端的原始调用者知道有错误。抛出的异常会绕过所有中间函数,并将错误直接传递到所需的位置,即原始调用站点。

void function3()
{
    @throw [NSException exceptionWithName:@"Test" reason:@"Test" userInfo:nil];
}

void function2()
{
    function3();
}

void function1()
{
    function2();
}

int main()
{
    @try
    {
        function1();
    }
    @catch(NSException *ex)
    {
        // handle exception that occurred 3 functions deep
    }
}

一般来说,由于内存管理的工作方式,您应该避免在 Objective-C 中将异常作为捕获可恢复错误的一般方法。在上述情况下,如果在function1function2function3 中分配了任何对象但没有自动释放,那么这些对象的内存将被泄漏。启用“完全异常安全”的 ARC 能够检测这些情况并适当地处理它们,但这仅适用于您自己代码中的 objects,而不适用于您可能使用的外部库分配的任何内存。一般认为您的应用程序不会从@throw 引发的异常中恢复。

查看更多详情in this Q&A

【讨论】:

    【解决方案2】:

    @throw 让你,等待它,抛出异常,为什么我们要抛出异常? 当发生异常情况时我们会抛出异常,例如,在下面的代码中,库存数组大小为零是没有意义的,因此针对这种特殊情况我们会抛出异常。

    NSString *getRandomCarFromInventory(NSArray *inventory) {
        int maximum = (int)[inventory count];
        if (maximum == 0) {
            NSException *e = [NSException
                             exceptionWithName:@"EmptyInventoryException"
                             reason:@"*** The inventory has no cars!"
                             userInfo:nil];
            @throw e;
        }
        int randomIndex = arc4random_uniform(maximum);
        return inventory[randomIndex];
    }
    

    这个例子的更多信息:http://rypress.com/tutorials/objective-c/exceptions.html (强调我的)

    iOS 或 OS X 可能会出现两种不同类型的问题 应用程序正在运行。异常代表程序员级别的错误 就像试图访问一个不存在的数组元素一样。 他们是 旨在通知开发人员意外情况 发生。因为它们通常会导致程序崩溃, 生产代码中应该很少出现异常。

    【讨论】:

    • 这通常是您不想抛出异常的情况。 Objective-C 中的异常应该通知应用程序处于不可恢复状态,这意味着应用程序在抛出异常后无法正常运行。
    • 这取决于从空库存中获得随机汽车是否可以恢复。如果库存中绝对必须有汽车,那么这可能是 NSException 的情况,另一方面,如果此函数可以返回 nil 并且原始调用者能够在没有汽车的情况下执行替代操作,则不应使用NSException
    【解决方案3】:

    如果操作失败并引发异常,例如:

    @try{ // code fails and raises an exception 
          if (!objectNotInMemory)
          {
              @throw exc; // presuming you already initialized NSException* exc
          }
    }
    @catch (NSException* e){ // deal with exception exc
        if ([[e reason] isEqualToString:@"Object not in memory"])
        UIAlertView* alert = [UIAlertView initWith...];
    }
    

    引发该异常的事物(在这种情况下,objectNotInMemory 不存在、nil 或 0)具有创建或传递某种 NSException 对象或消息的 @throw{} 指令。然后可以在@catch{} 块中捕获此异常对象,或者如果被忽略,则会提醒操作系统关闭应用程序进程。

    必须抛出异常才能被捕获。

    更多阅读 Apple 文档(您应该对此感到满意):

    @try — 定义一个作为异常处理域的代码块: 可能引发异常的代码。

    @catch() — 定义一个包含用于处理异常的代码的块 在@try 块中抛出。 @catch 的参数是例外 本地抛出的对象;这通常是一个 NSException 对象,但可以 是其他类型的对象,例如 NSString 对象。

    @finally — 定义一个相关代码块,随后 无论是否抛出异常都执行。

    @throw — 抛出异常;该指令在 NSException 的 raise 方法的行为。你通常扔 NSException 对象,但不限于它们。了解更多信息 关于@throw,请参阅“抛出异常”。

    【讨论】:

    • 感谢您的详细回答。所以你说如果objectNotInMemory 不为真,那么抛出exc,这是一个异常。然后catch代码块捕获异常并将e设置为exc?我们可以考虑引用异常对象的 e 和 exc 指针吗?
    • 初始化exc,你会不会只做NSException * exc = [[NSException alloc] init];
    • @somid- 是的,你可以像任何对象一样初始化它。你可以[[...alloc] init],然后一个一个设置属性,但我更喜欢[[...alloc] initWithName:(NSString*) reason:(NSString*) userInfo:(NSDictionary*)]
    • 另请注意,与引发异常来弥补潜在错误相比,首先编写健壮的代码要好得多。
    • @user:您关于通过值而不是通过引用传递参数的评论是错误的。 @catch 确实收到了抛出的相同对象,因为 (a) 异常是不可变的,复制它是没有意义的,而 (b) 因为虽然传递了参数按 C 中的值,指针是值,Objective-C 对象 [几乎] 总是由指针处理,而 (c) 因为它可以用一个最小的例子来验证。创建一个NSException 对象,并在使用@throw 将其抛出之前,记录其地址。然后在@catch 块中,再次记录其地址。还是一样。
    猜你喜欢
    • 2013-08-27
    • 2021-10-13
    • 1970-01-01
    • 2014-03-08
    • 1970-01-01
    • 2020-09-09
    • 2014-09-08
    • 1970-01-01
    • 2020-07-19
    相关资源
    最近更新 更多