【问题标题】:Swift Error Handling For Methods That Do Not Throw [duplicate]不抛出的方法的快速错误处理[重复]
【发布时间】:2017-06-19 01:42:32
【问题描述】:

如何处理未明确抛出的方法或代码的错误?

将其包装为 do / catch 块会导致编译器警告:

"'catch' block is unreachable because no errors are thrown in 'do' block"

来自 C# / JAVA 背景,这至少可以说是一件奇怪的事情。作为一名开发人员,我应该能够在 do/catch 块中保护和包装任何代码块。仅仅因为一个方法没有明确地用“throw”标记并不意味着不会发生错误。

【问题讨论】:

  • 如果没有明确的throw,那么就没有什么可捕获的了。如果没有任何东西被抛出,do/catch 有什么意义?
  • 好吧,仅仅因为一个方法没有明确地“抛出”并不意味着不会发生运行时错误:)
  • 这意味着没有可捕获的错误。您无法捕获无法捕获的运行时错误。
  • Java 有无法捕获的异常(错误)。斯威夫特也不例外。
  • @AlexVPerl 这不是一个糟糕的设计决定——运行时的致命错误不应该被捕获,因为它们表示程序员错误(例如访问超出范围的索引集合或强制展开 nil)。你不应该发现这样的错误,你应该修复你的代码,这样它们就不会首先发生。

标签: swift error-handling do-catch


【解决方案1】:

错误和异常之间是有区别的。 Swift 只处理显式抛出的错误,并且没有处理异常的本机能力。正如其他人所评论的那样,必须抛出错误,并且您无法捕捉未抛出的内容。

相比之下,Objective-C @try-@catch 处理异常,而不是错误。一些 objc 方法可能会导致异常,但不会以任何方式向编译器声明它们。例如文件句柄.write。此类异常更接近于 Java 的 RuntimeException,后者也不需要声明。

在某些情况下,例如文件处理,在 Swift 中干净地处理 异常 会很好,并且可以通过使用 Objective-C 包装器来实现。见http://stackoverflow.com/questions/34956002/how-to-properly-handle-nsfilehandle-exceptions-in-swift-2-0

此处转载的代码:

#ifndef ExceptionCatcher_h
#define ExceptionCatcher_h

#import <Foundation/Foundation.h>

NS_INLINE NSException * _Nullable tryBlock(void(^_Nonnull tryBlock)(void)) {
    @try {
        tryBlock();
    }
    @catch (NSException *exception) {
        return exception;
    }
    return nil;
}

#endif /* ExceptionCatcher_h */

然后从 Swift 调用它:

let exception = tryBlock {
   // execute dangerous code, e.g. write to a file handle
   filehandle.write(data)
}

if exception != nil {
   // deal with exception which is of type NSException
}

【讨论】:

    【解决方案2】:

    我怀疑您想要捕获未明确标记为“抛出”的错误。

    这毫无意义。 除了明确标记为“抛出”的错误之外,您无法捕获其他错误。 所以,这个警告是有效的。

    对于本例,如果执行,将出现fatal error: Index out of range。 这是运行时错误,您无法捕捉到它。

    对于这个例子,你应该像这样检查元素大小,而不是进行 try-catch 错误处理:

    【讨论】:

      【解决方案3】:

      面对从无法抛出的方法抛出的异常。发现这个异常是从 API 的objective-c 部分抛出的。因此,您应该使用 Objective-c 以旧式方式捕获它。

      首先创建objective-c 类,该类在init 方法中包含几个块- 用于try、catch 和finally。

      #import <Foundation/Foundation.h>
      
      /**
       Simple class for catching Objective-c-style exceptions
       */
      @interface ObjcTry : NSObject
      
      /**
       *  Initializeer
       *
       *  @param tryBlock
       *  @param catchBlock
       *  @param finallyBlock
       *
       *  @return object
       */
      - (_Nonnull id)initWithTry:(nonnull void(^)(void))tryBlock catch:(nonnull void(^)( NSException * _Nonnull exception))catchBlock finally:(nullable void(^)(void))finallyBlock;
      
      @end
      

      在 .m 文件中:

      #import "ObjcTry.h"
      
      @implementation ObjcTry
      
      - (_Nonnull id)initWithTry:(nonnull void(^)(void))tryBlock catch:(nonnull void(^)( NSException * _Nonnull exception))catchBlock finally:(nullable void(^)(void))finallyBlock
      {
          self = [super init];
          if (self) {
              @try {
                  tryBlock ? tryBlock() : nil;
              }
              @catch (NSException *exception) {
                  catchBlock ? catchBlock(exception) : nil;
              }
              @finally {
                  finallyBlock ? finallyBlock() : nil;
              }
          }
          return self;
      }
      
      @end
      

      其次,将其标头添加到 Bridging Header 文件中。

      #import "ObjcTry.h"
      

      并像这样在您的 swift 代码中使用它:

      var list: [MyModel]!
      _ = ObjcTry(withTry: {
          // this method throws but not marked so, you cannot even catch this kind of exception using swift method.
          if let items = NSKeyedUnarchiver.unarchiveObject(with: data) as? [MyModel] {
               list = items
          }
      }, catch: { (exception: NSException) in
          print("Could not deserialize models.")
      }, finally: nil)
      

      【讨论】:

        【解决方案4】:

        您的问题在 Swift 中是不可能实现的,因为 Swift 无法处理运行时错误,例如越界、访问冲突或运行时强制解包失败。如果发生任何这些严重的编程错误,您的应用程序将终止。

        一些提示:

        长话短说:不要在 Swift 中简化错误处理。始终保持安全。

        解决方法:如果您绝对必须捕获运行时错误,则必须使用进程边界来保护。 Run another program/process 并使用管道、套接字等进行通信。

        【讨论】:

          【解决方案5】:

          正如其他人提到的,你不应该捕获这些错误,你应该修复它们,但如果你想在程序终止之前执行更多代码,请使用 NSSetUncaughtExceptionHandler in AppDelegate in @ 987654323@函数。

          功能说明:

          更改顶级错误处理程序。

          设置顶级错误处理 功能,您可以在程序之前执行最后一分钟的记录 终止。

          【讨论】:

            【解决方案6】:

            你根本做不到。整个do-try-catchdo-catch 语句旨在用于捕获未处理的错误和...

            我的意思是,如果首先没有发生错误,那么捕获错误是没有意义的……我看不出你为什么要这样做,你只会让编译器无缘无故地生气。

            如果您使用 if letguard let 语句安全地打开 optional 也是同样的情况

            guard let smth = smthOpt?.moreSpecific else { return }
            
            //Compiler gives warning -  unused variable smth. You wouldn't declare the variable and then not use it, or you would? 
            

            Simply Do-Catch 并不是为了安全使用,而且我看不出有任何理由在不处理需要捕获的风险操作时使用它......

            更多理解请看:

            https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html

            【讨论】:

            • Swift 或 ios 即使在非风险函数上也可能表现出意外。 swift中没有针对意外行为的预防措施,这是由于不成熟。
            • lol答案和选的差不多
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-11-24
            • 2018-01-12
            • 2016-02-07
            • 1970-01-01
            • 2016-02-05
            • 1970-01-01
            相关资源
            最近更新 更多