我应该如何在Swift中使用NSSetUncaughtExceptionHandler

bil*_*lly 19 error-handling ios swift

在Objective-C,我调用该NSSetUncaughtExceptionHandler(&exceptionHandler)方法来记录异常.它如何在Swift中调用?

Mar*_*n R 48

从Swift 2(Xcode 7)开始,您可以将Swift函数/闭包传递给带有C函数指针的参数.从Xcode 7发行说明:

对C函数指针的本机支持:可以使用闭包或全局函数调用带有函数指针参数的C函数,但限制是闭包不能捕获任何本地上下文.

所以这个编译和工作:

func exceptionHandler(exception : NSException) {
    print(exception)
    print(exception.callStackSymbols)
}

NSSetUncaughtExceptionHandler(exceptionHandler)
Run Code Online (Sandbox Code Playgroud)

或者使用"内联"封口:

NSSetUncaughtExceptionHandler { exception in
    print(exception)
    print(exception.callStackSymbols)
}
Run Code Online (Sandbox Code Playgroud)

这与相应的Objective-C代码完全相同:它捕获了其他未捕获NSException的代码.所以这将被抓住:

let array = NSArray()
let elem = array.objectAtIndex(99)
Run Code Online (Sandbox Code Playgroud)

注意: - 它没有捕获任何Swift 2错误(from throw)或Swift运行时错误,因此不会捕获:

let arr = [1, 2, 3]
let elem = arr[4]
Run Code Online (Sandbox Code Playgroud)

  • 哦!我没有注意到......那么有什么方法可以捕获快速的运行时错误? (2认同)
  • 如果你想要更漂亮的堆栈跟踪,请使用`exception.callStackSymbols.joinWithSeparator("\n")` (2认同)
  • 有人可以解释一下使用此代码的位置吗?我把它放在didFinishLaunchingWithOptions我appdelegate,但它不起作用 (2认同)

jou*_*jou 13

更新

使用Swift 2,您可以将Swift函数和闭包作为C函数指针传递.请参阅下面的Martin R的答案.

原始答案

你不能,从Xcode 6 beta 6开始.

Swift确实支持传递函数指针,但它们的处理方式与非透明指针非常相似.既不能定义指向Swift函数的C函数指针也不能在Swift中调用C函数指针.

这意味着你NSSetUncaughtExceptionHandler()从Swift 调用,但处理程序必须在Objective-C中实现.你需要一个像这样的头文件:

volatile void exceptionHandler(NSException *exception);
extern NSUncaughtExceptionHandler *exceptionHandlerPtr;
Run Code Online (Sandbox Code Playgroud)

在实现中,你需要这样的东西:

volatile void exceptionHandler(NSException *exception) {
    // Do stuff
}
NSUncaughtExceptionHandler *exceptionHandlerPtr = &exceptionHandler;
Run Code Online (Sandbox Code Playgroud)

在Swift桥接头中导入头文件后,您可以像往常一样设置异常处理程序:

NSSetUncaughtExceptionHandler(exceptionHandlerPtr)
Run Code Online (Sandbox Code Playgroud)


Yun*_* T. 5

以这种方式在重新打开后续应用程序时可以看到错误。

此代码适用于 swift 4. 添加didFinishLaunchingWithOptions()

NSSetUncaughtExceptionHandler { exception in
            print("Error Handling: ", exception)
            print("Error Handling callStackSymbols: ", exception.callStackSymbols)

            UserDefaults.standard.set(exception.callStackSymbols, forKey: "ExceptionHandler")
            UserDefaults.standard.synchronize()
        }
Run Code Online (Sandbox Code Playgroud)

并在 fistViewController 中添加代码 viewLoad()

// ERROR ExceptionHandler
        if let exception = UserDefaults.standard.object(forKey: "ExceptionHandler") as? [String] {

            print("Error was occured on previous session! \n", exception, "\n\n-------------------------")
            var exceptions = ""
            for e in exception {
                exceptions = exceptions + e + "\n"
            }
            AlertFunctions.messageType.showYesNoAlert("Error was occured on previous session!", bodyMessage: exceptions, {

            }, no: {
                UserDefaults.standard.removeObject(forKey: "ExceptionHandler")
                UserDefaults.standard.synchronize()
            })
        }
Run Code Online (Sandbox Code Playgroud)

编辑:代码工作。但是您需要在出错后重新打开您的应用程序。


Mil*_*mic 5

斯威夫特 5:

1. 在 AppDelegate 中添加这个方法:

    func storeStackTrace() {
        NSSetUncaughtExceptionHandler { exception in
            print(exception)
            // do stuff with the exception
        }
     }
Run Code Online (Sandbox Code Playgroud)

2. 从 didFinishLaunchingWithOptions 调用此方法并在之后立即引发异常

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            storeStackTrace()

            let exception = NSException(name: NSExceptionName(rawValue: "arbitrary"), reason: "arbitrary reason", userInfo: nil)
            exception.raise()


    }
Run Code Online (Sandbox Code Playgroud)

3. 跟踪控制台输出,它会立即打印出您刚刚提出的异常,并从您提供的原因开始。

  • 嗨@Dhyaan,它应该崩溃,这是预期的:)您故意通过以下方式导致崩溃:Exception.raise()。目的是跟踪上面storeStackTrace()方法中的异常 (2认同)