展开Nil

时间:2016-11-16 11:45:27

标签: ios swift exception-handling signals

我正在构建一些基于this blog post的基本崩溃记录系统( ,我知道PLCRashReporter, 否< / strong> ,我无法使用它,需要自己动手,无论多么有限。谢谢。)

我的代码为大多数信号注册了异常处理程序(带NSSetUncaughtExceptionHandler())和信号处理程序:

SIGQUIT
SIGILL
SIGTRAP
SIGABRT
SIGEMT
SIGFPE
SIGBUS
SIGSEGV
SIGSYS
SIGPIPE
SIGALRM
SIGXCPU
SIGXFSZ

似乎可以使用基本的Objective-C工作,例如“无法识别的选择器发送到实例......”等等。

接下来,我尝试使用以下 Swift 代码:

var empty:String! = nil

let index = empty.startIndex // < KA-BOOM!

...但是没有捕获抛出的异常EXC_BAD_INSTRUCTION(我的处理程序没有被调用),而是让我熟悉:

  

致命错误:在解包可选值时意外发现nil

...在Xcode控制台中。

我缺少什么?

This answer表示可以使用SIGTRAP处理此类运行时错误;但是我已经处理了这个信号而且它似乎没有用。

ADDENDUM:似乎没有适用于Swift运行时错误的集中式异常处理系统(越界,无解包等);见this post。但是,Xcode仍然能够与EXC_BAD_INSTRUCTION崩溃,所以我的问题是:这怎么可能,为什么我的信号处理程序不能处理这个?

ADDENDUM 2:为了安全起见,我尝试为signal.h中定义的所有 20+信号注册我的信号处理程序(不仅仅是上面列出的信号);仍然没有变化。

ADDENDUM 3 :Apple的官方文档Understanding and Analyzing Application Crash Reports包含以下代码段:

  

跟踪陷阱[EXC_BREAKPOINT // SIGTRAP]

     

与异常退出类似,此异常旨在提供   附加调试器有机会在特定的情况下中断进程   指出它的执行。您可以从自己的触发器中触发此异常   代码使用__builtin_trap()函数。如果没有附加调试器,   该流程终止,并生成崩溃报告。

     

低级库(例如libdispatch)将捕获进程   遇到致命的错误。有关错误的其他信息可以   可以在崩溃的“附加诊断信息”部分找到   报告,或在设备的控制台中。

     

如果出现意外情况,Swift代码将以此异常类型终止   在运行时遇到条件,例如:

     
      
  • 具有零值的非可选类型
  •   
  • 强制类型转换失败
  •   
     

查看Backtraces以确定意外情况的位置   遇到。其他信息也可能已记录到   设备的控制台。您应该修改崩溃位置的代码   优雅地处理运行时故障。例如,使用Optional   绑定而不是强制打开可选项。

(强调我的)

仍然:为什么我无法使用SIGTRAP信号处理程序处理此问题?

1 个答案:

答案 0 :(得分:3)

TL; DR:当调试器附加时,信号处理程序正常工作。

为了了解发生了什么,我设置了一个小型演示项目,我在其中为SIGUSR1注册了一个信号处理程序(其中一个用户定义的&#39;信号可用),随后发送使用kill()函数向我的进程发出信号:

kill(0, SIGUSR1);

起初,我无法让Xcode的调试器跳转到我的信号处理程序,而是停在kill()调用的行,突然显示为红色,就像在我的问题中。

在阅读this question and its answers之后,让我感到震惊的是,调试器必须非常依赖依赖信号,以便能够停止/恢复程序执行,例如在断点处。

使用其中一个答案中指定的符号断点:

process handle SIGUSR1 -n true -p true -s false

...我能够使Xcode 停止此命令:

kill(pid, SIGUSR1);

...而是在调试时跳转到我的信号处理程序。我甚至可以进入信号处理程序并逐个执行它的语句;显示其中的警报视图等

虽然我无法使用SIGTRAP(甚至SIGABRT)获得相同的结果,但我的信号处理程序被调用(我的崩溃日志 保存到磁盘!)当我在没有附加调试器的情况下启动我的应用程序时(例如,通过点击主屏幕上的应用程序图标)并让它像我提到的那样抛出Swift运行时错误在我的问题。

我对为什么我能够拦截unrecognized selector sent to instance...的猜测似乎是,作为 Objective-C异常,它是一个完全不同的野兽 Unix信号,与调试器的工作无关(除非你为Objective-C异常设置异常断点?)。

使用不相关的函数NSSetUncaughtExceptionHandler()设置处理程序的事实应该是一个提示......

(我在这里谈论我的有限知识,所以请随意添加你认为合适的更正的答案/评论)