在Swift中捕获NSException

sil*_*vsk 65 cocoa-touch exception foundation nsexception swift

Swift中的以下代码引发NSInvalidArgumentException异常:

task = NSTask()
task.launchPath = "/SomeWrongPath"
task.launch()
Run Code Online (Sandbox Code Playgroud)

我该如何捕捉异常?据我所知,Swift中的try/catch是针对Swift中抛出的错误,而不是针对像NSTask这样的对象引发的NSExceptions(我猜这是用ObjC编写的).我是Swift的新手,所以可能是我错过了一些明显的东西......

编辑:这是一个关于bug的雷达(特别是对于NSTask):openradar.appspot.com/22837476

fre*_*tag 121

下面是一些将NSExceptions转换为Swift 2错误的代码.

现在你可以使用了

do {
    try ObjC.catchException {

       /* calls that might throw an NSException */
    }
}
catch {
    print("An error ocurred: \(error)")
}
Run Code Online (Sandbox Code Playgroud)

ObjC.h:

#import <Foundation/Foundation.h>

@interface ObjC : NSObject

+ (BOOL)catchException:(void(^)(void))tryBlock error:(__autoreleasing NSError **)error;

@end
Run Code Online (Sandbox Code Playgroud)

ObjC.m

#import "ObjC.h"

@implementation ObjC 

+ (BOOL)catchException:(void(^)(void))tryBlock error:(__autoreleasing NSError **)error {
    @try {
        tryBlock();
        return YES;
    }
    @catch (NSException *exception) {
        *error = [[NSError alloc] initWithDomain:exception.name code:0 userInfo:exception.userInfo];
        return NO;
    }
}

@end
Run Code Online (Sandbox Code Playgroud)

不要忘记将其添加到"*-Bridging-Header.h":

#import "ObjC.h"
Run Code Online (Sandbox Code Playgroud)

  • 哇,这仍然是在Swift 2.x中捕获NSException的唯一方法吗?这在3.0中改变了吗? (4认同)
  • 直到我在`@ catch`块中添加了一个显式的`return`,它才对我有效.编辑执行此操作(并删除了不必要的`let error`,因为错误_always_作为"错误"到达常规catch块) (4认同)
  • FWIW,在Swift 3中,你还可以将`__attribute __((noescape))`添加到`tryBlock`类型中,这样你就可以在使用它时调用`self`上的方法,而不需要明确地包含`self`.这使得完整声明`+(BOOL)catchException:(__ attribute __((noescape))void(^)())tryBlock错误:(_ _ autoreleasing NSError**)错误;`. (3认同)

BPC*_*orp 12

我建议创建一个C函数来捕获异常并返回NSError.然后,使用此功能.

该函数可能如下所示:

NSError *tryCatch(void(^tryBlock)(), NSError *(^convertNSException)(NSException *))
{
    NSError *error = nil;
    @try {
        tryBlock();
    }
    @catch (NSException *exception) {
        error = convertNSException(exception);
    }
    @finally {
        return error;
    }
}
Run Code Online (Sandbox Code Playgroud)

有了一点桥接帮助,你只需要打电话:

if let error = tryCatch(task.launch, myConvertFunction) {
    print("An exception happened!", error.localizedDescription)
    // Do stuff
}
// Continue task
Run Code Online (Sandbox Code Playgroud)

注意:我没有真正测试它,我找不到一个快速简单的方法在Playground中使用Objective-C和Swift.


mm2*_*001 9

TL; DR:使用Carthage包含 https://github.com/eggheadgames/SwiftTryCatch 或CocoaPods以包含 https://github.com/ravero/SwiftTryCatch.

然后你可以使用这样的代码,而不用担心会崩溃你的应用程序:

import Foundation
import SwiftTryCatch

class SafeArchiver {

    class func unarchiveObjectWithFile(filename: String) -> AnyObject? {

        var data : AnyObject? = nil

        if NSFileManager.defaultManager().fileExistsAtPath(filename) {
            SwiftTryCatch.tryBlock({
                data = NSKeyedUnarchiver.unarchiveObjectWithFile(filename)
                }, catchBlock: { (error) in
                    Logger.logException("SafeArchiver.unarchiveObjectWithFile")
                }, finallyBlock: {
            })
        }
        return data
    }

    class func archiveRootObject(data: AnyObject, toFile : String) -> Bool {
        var result: Bool = false

        SwiftTryCatch.tryBlock({
            result =  NSKeyedArchiver.archiveRootObject(data, toFile: toFile)
            }, catchBlock: { (error) in
                Logger.logException("SafeArchiver.archiveRootObject")
            }, finallyBlock: {
        })
        return result
    }
}
Run Code Online (Sandbox Code Playgroud)

@BPCorp接受的答案按预期工作,但正如我们所发现的,如果您尝试将此Objective C代码合并到大多数Swift框架中然后运行测试,那么事情会变得有趣.我们遇到了无法找到类函数的问题(错误:使用未解析的标识符).因此,由于这个原因,以及一般易用性,我们将其打包为一般用途的Carthage库.

奇怪的是,我们可以在其他地方使用Swift + ObjC框架而没有任何问题,它只是对框架的单元测试而言正在挣扎.

要求PR!(让它成为一个组合CocoaPod和Carthage构建,并进行一些测试会很好).

  • 对于STC,我建议只将文件复制到项目中.尝试通过包管理器导入和更新STC时,我遇到了太多问题.它有大约173种不同的叉子.它们支持Swift 1,Swift 2和/或Swift 3.它们支持Carthage,CocoaPods和/或SPM.它们支持iOS,macOS,tvOS和/或watchOS.但是没有一个分支支持我需要的特定组合(或者在一年内更新过),而且我浪费了太多时间.选择一个,将其复制到您的项目中,然后继续进行更多有用的工作. (4认同)