Xcode 小技巧

865 阅读4分钟

引子:编译原理

程序到可执行文件需要经过四个步骤:预处理,编译,汇编和链接。

编译过程

  1. 词法分析,将代码的字符序列分割成一系列的词法单元(token);
  2. 语法分析,生成抽象语法树(AST); 3. 语义分析,检查表达式是否合法有效;
  3. 源代码优化器,用于生成与机器无关的中间代码表示(IR);
  4. 最后是代码生成器和目标代码优化器,用于生成汇编代码以及做一些优化处理。

静态语义和动态语义

  • 编译过程中所能分析的语义是静态语义,是在编译期间就已经可以确定的语义,比如除数不能为 0;
  • 相对的动态语义则是在运行时才能确定的语义。

静态语义问题集中显示在 Issue navigator 的 Buildtime 一栏中,如我们经常遇到的错误、警告、静态分析问题以及单元测试失败信息:

Screen Shot 2019-11-15 at 2.34.36 PM.png
Screen Shot 2019-11-15 at 2.34.46 PM.png
Screen Shot 2019-11-15 at 2.36.47 PM.png

那么程序运行时的动态语义分析问题我们又该如何定位和排查呢?

Runtime Checking: 运行时检查工具

01.Memory Graph: 实战解决闭包引用循环问题

测试环境要求:Xcode 8.0 beta 及以上

闭包循环引用后,选择这个按钮:

225849-81486a8ba4f85ccd.webp

这个时候就进入了断点模式,可以查看 issue 面板,注意选择右边 Runtime:

225849-5d7c2230bc3d4755.webp

有很多叹号说明就有问题了。看内存中 object 的名字,有一条是 Closure captures leaked。展开后点击就可以看到这个 issue 对应的内存图形展示在中间的面板中。

当然了,我们更多的时候是在debug页面下查看:

225849-2c8ba810774336fb.webp

有了这个图就很容易看出来了:myView保持了action,action保持了testMethod,testMethod中因为设置了vc的label所以也保持了VC。所以我们可以确定:方法中隐式的self的捕捉策略是strong。这样直接把方法传入子view中会引起引用循环。

02.Thread Sanitizer:线程消除器

继 Address Sanitizer 之后,Xcode8 中加入 Thread Sanitizer 用于检查一些线程问题,并会显示在 runtime issue 列表中,使用 Thread Sanitizer 需如下图所示开启,重新编译运行后即可。

thread_sanitizer.jpg

Thread Sanitizer 主要检测以下问题:

  • 使用了未初始化的 mutexes
  • Thread leaks,如缺少 pthread_join
  • 在 signal handlers 中的不安全调用,如调用 malloc
  • 在错误的线程中做 unlock
  • 最重要的一点:Data races 问题

凡是通过 Thread Sanitizer 检查出来问题,都代表着有很严重的隐患,那么,赶快修复吧!

03.循环布局检测

当你进入某个界面或点击某个按钮后,发现屏幕不再响应事件,然后进入无限等待,debug下可以看到CPU满负荷,RAM也不断增加,那么有可能就进入了循环布局状态。

可在 Launch Arguments 中添加 -UIViewLayoutFeedbackLoopDebuggingThreshold,设置循环布局阀值,如100,然后当循环布局次数超过阀值时会抛出异常,此时通过 po [_UIViewLayoutFeedbackLoopDebugger layoutFeedbackLoopDebugger] 可输出详细信息。

auto_layout_loop_threshold.jpg

04.Register read:读取注册信息

平时是否有过crash在没有源码的第三方库或系统库中,而检查自己代码又没有发现任何问题?那么试试 register 命令吧,可能会有意向不到的效果。

通过 register read 可以读取当前状态下寄存器存储的变量,在没有源码的情况下运气好就可以获取到一些非常有用的信息,毕竟很有可能是你传入的某个错误值导致的最终 crash,而这个值就可能从寄存器中取到,从而快速定位原因。

register 还有一个非常有用的特性,当刚进入某一函数时,可通过 register read $arg1 $arg2 ... 读取函数的各个参数值。

05.本地化检查

首先需要如下方式开启,Static Analysis 将会检查 UI元素 的文字设置是否使用了 NSLocalizedString

localizability.jpg