原文链接,原文日期:2018-08-14
译者:lbj
当我在编译运行 FastScripts时出现了如下问题
FastScripts [...] is calling TIS/TSM in non-main thread environment,
ERROR : This is NOT allowed. Please call TIS/TSM in main thread!!!
不知道是什么原因导致的这个问题。
有时候苹果添加了想这样的log信息都提供了足够的解决信息。有的是建议我们停止使用过时的方法、或者像现在这种场景中,提供一个象征性的设置为0的断点并且完全对应了代码所在。例如,我打开控制台应用程序的快速调查显示:
default 11:54:18.482226 -0400 com.apple.WebKit.WebContent
Set a breakpoint at SLSLogBreak to catch errors/faults as they are logged.
这个特定的警告好像和我的程序并没有什么关系,但如果是这样的,我需要去学习更多有关TIS/TSM 相关的东西,但是我并不知道改怎么做,我甚至都不知道用了TIS/TSM ,什么是TIS/TSM ??
在苹果平台工作了足够久之后我知道了TSM代表的是文本服务的工具,然而我还是不知道是否用过这个东西、或正在我的程序中使用着这个框架、这是苹果还是我在使用的东西?
理想情况下我们可以通过设置断点来打印相关信息,但现在的情况出乎意料的困难啊。我们有NSLog, os_log, printf, fprintf, write等方法去获取信息。我可以通过全面的方法捕捉任何写入控制台的方法,但是我是否需要通过这种方法去获取信息呢?(在这种特殊的情况下,我深入研究了CFLog)。
这是一个场景,结合lldb强大的“正则表达式断点”和“断点指令”可以帮助很大。早在我的应用程序的启动,警告消息记录,我就进入了lldb,添加断点:
(lldb) break set -r TIS|TSM.*
我觉得无论是什么函数导致这个问题都会包含与这个前缀相关的框架,这是一个比较可行的猜测。
Breakpoint 5: 634 locations.
点击继续让我的程序继续运行,但是它有634的相关的断点,时不时的出现。我更倾向于让它自己处理并自行整理出细节:
(lldb) break command add 5
Enter your debugger command(s). Type 'DONE' to end.
> bt
> c
> DONE
(lldb) c
Process 16022 resuming
break command add 的功能是
Add LLDB commands to a breakpoint, to be executed whenever the breakpoint
is hit. If no breakpoint is specified, adds the commands to the last
created breakpoint.
bt 的功能是显示当前堆栈
c 的功能是继续执行所有进程
这一系列命令的作用是在命中断点5的时候调用bt方法获取调用堆栈,然后继续运行,在程序运行之后,就可以查看最近被调用的命令了。
thread #7, stop reason = breakpoint 5.568
frame #0: 0x00007fff2cd520fd HIToolbox`TSMGetInputSourceProperty
frame #1: 0x00000001003faef2 RSFoundation`-[RSKeyboardStatus update](self=0x00006000002b8c00, _cmd="update") at RSKeyboardStatus.m:56
[...]
Command #2 'c' continued the target.
2018-08-14 12:15:40.326538-0400 FastScripts[16022:624168] pid(16022)/euid(501) is calling TIS/TSM in non-main thread environment, ERROR : This is NOT allowed. Please call TIS/TSM in main thread!!!
经过查找之后发现以上问题,很显然,这是我的代码,我调用TSM的方法去处理FastScripts的键盘的快捷键功能, thread #7中很显然能够发现这不是处于主线程中,我应该感到羞愧。。。。
但是我很自豪能够通过lldb定位到了问题所在,下次你如果遇到无法定位问题的时候,可以尝试通过基于正则表达式的断点和一系列的命令来确定问题。
总结
当遇到无法定位的问题可以尝试通过lldb和正则来定位问题。
就如原作者遇到了的问题做了如下几点:
1.通过设置一个正则表达式的断点来定位问题;
2.因为有太多满足条件的情况原作者通过lldb批量处理调用堆栈内容;
3.查看日志最终定位到问题。
更多的lldb方法,在lldb中通过help命令去获取