Mac 工具(调试工具、命令、常用软件)MacOS开发 技术集锦iOS开发 技术集锦

Xcode开发选项设置与调试工具

2017-03-26  本文已影响729人  jinstar520

构建测试平台

获取隐藏的文件信息,在终端输入如下命令:

defaults write com.apple.Finder AppleShowAllFiles TRUE 
defaults write com.apple.Finder Showpathbar -bool true
defaults write com.apple.Finder _FXShowPosixPathInTitle -bool true
defaults write NSGlobalDomain AppleShowAllExtensions -bool true
chflags nohidden ~/Library/

通过上述设置,Finder中的所有文件都变为可见,包括以“.”开头的隐藏文件。此外还会显示详细的文件路径和扩展信息,最为重要的是能看到与用户相关的Library目录,iOS模拟器和Xcode的数据都存储在此目录下。

chflags命令将那些苹果认为会迷惑用户的隐藏文件全部显示了出来,例如/tmp或/usr。这样更方便查看模拟器目录。

把$SIMPATH添加到Finder的侧边栏,便于访问。默认设置下,Finder没有$SIMPATH。想要实现上述设置,在终端输入以下命令:

cd ~/Library/Developer
open .

Developer文件夹下有三个目录。其中CoreSimulator、Xcode是我们常用的。将Developer拖拽到Finder侧边栏中。

屏幕快照 2017-03-26 下午12.33.07.png

Xcode构建设置

首先将警告视为错误。大部分警告都是由clang产生的,它属于Xcode编译器的前端(frontend),值得认真对待。这样做可以减少代码复杂度、确保语法正确,还可以捕获那些难以发现的错误,比如无符号问题或是格式字符串漏洞,看如下代码:

- (void)validate:(NSArray *)someTribbles withValue:(NSInteger)desired{
    if(desired > [someTribbles count]) {
        
    }
}

NSArray的count方法返回一个无符号整形(NSUInteger),if判断语句会提示 “'NSInteger' (aka 'long') and 'NSUInteger' (aka 'unsigned long'”警告。启用将警告视为错误的选项,从而使clang标记该类型为bug,运行工程将会失败。

这里的意思是说启用项目构建配置中的更多警告模式,并将警告提升到bug的高度,强迫自己尽可能在开发的早期阶段解决掉一些隐患,培养良好的编码习惯。

在target->build setting->Warning Policies下,把Treat Warnings as Errors 设置为YES。

屏幕快照 2017-03-26 下午1.06.59.png

在Custom Compiler Flags下,设置Other Warning Flags,这里有-Wall、-Wextra、-Weverything三个值可选,含义如下:

这里推荐-Wall和-Wextra,或者-Wextra,设置后运行程序警告数成倍的增长,看看其中哪些是真正的bug。

屏幕快照 2017-03-26 下午1.21.17.png

Clang和静态分析(Static Analyzer)

静态分析一般指的是使用工具来分析代码并找出安全漏洞。这可能涉及识别一系列危险的API,或分析通过应用程序的数据流,来标识潜在不安全的程序输入。

Xcode中提供了一个UI界面工具。用户可以使用该工具很直观的完成逻辑追踪、代码漏洞以及通用API误用等分析操作。但有一些重要特性,Xcode默认是禁止。其中值得关注的特性有:对C语言库函数等经典威胁的检查,比如针对strcpy和strcat的检查就是默认关闭的。你可以在项目或Target设置中开启这些特性:

屏幕快照 2017-03-26 下午1.33.09.png

在Xcode8中,静态分析能够检测出三种新的错误, 它们分别是Localizability、Instance Cleanup、Nullability。

屏幕快照 2017-03-26 下午1.46.12.png

Sanitizer和动态分析

在edit scheme->Diagnostics->Runtime Sanitizer中勾选相应的Sanitizer选项。

屏幕快照 2017-03-26 下午6.44.40.png

勾选了相应的选项并不代表你就能使用 Sanitizer 来Check代码了, 你还必须重新run一下代码,为什么呢?

这就必须说说整个代码 build flow 了. 如下图所示, 通过勾选了对应的选项, Xcode 会向 clang 传递一个特定的参数, 然后生成一个独特的 binary, 然后这个 binary 会和 Thread Sanitizer 或者 Address Sanitizer 的 dylib 链接在一起. 这样 Sanitizer 就实现了它想要达到的功能.

406302-b3a58fd1cf107857.jpg

Address Sanitizer(ASan)是一个类似Valgrind的动态分析工具,ASan可以检测出堆、栈溢出和释放后又被使用的bug,还能找到关键的安全漏洞。ASan会对性能产生一些影响(程序执行速度会慢一些),因此不要在发行版本中启用这个选项,但是在测试、质量保证检测或是缺陷测试阶段,使用这一特性带来便利吧。ASan能检查以下类型的错误:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    char *buffer = malloc(10);
    buffer[10] = 'A';
    free(buffer);
}

运行上面的代码,在开启ASan时,程序会崩溃在“buffer[10] = 'A';”这一行,并显示相应的崩溃类型。在不开启ASan时,不添加任何断点时,程序会崩溃在main函数里;添加任何断点后,程序不会崩溃。

问题很明显,这是一个数组越界,开启ASan后会直接定位到问题发生的地方,不开启的话,阿弥陀佛了。

让我们想想自己在调试线程方面的 bug 时, 有哪些令人记忆深刻的东西:

在Address Sanitizer下面勾选Thread Sanitizer。至于 Thread Sanitizer下面的那个Pause on Issues的选项就是说,如果你想一个一个看runtime issue就勾选它,如果你不想这样,就不要勾选它, 具体是个神马感觉,你自己试试喽。

如果你喜欢使用 Comman-Line ,那么请记住下面的代码

//Compile and Link with TSan
$ clang -fsanitize=thread source.c -o executable
$ swift -sanitize=thread source.swift -o executable
$ xcodebuild -enableThreadSanitizer YES

//Stop after the first error
$ TSAN_OPTIONS=halt_on_error=1 ./executable

TSan现在只支持64位macOS,以及64位的iOS和tvOS的模拟器,并不支持真机调试和watchOS。

那么TSan作为一个能够检查线程错误的工具, 它能检查以下类型的错误:

那么我们拿下面的这段代码来举例:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self resetStatue];
    pthread_mutex_init(&(_mutex), NULL);
}

- (void)resetStatue{
    [self acquireLock];
    self.dataArray = nil;
    [self releaseLock];
}

- (void)acquireLock{
    pthread_mutex_lock(&_mutex);
}

- (void)releaseLock{
    pthread_mutex_unlock(&_mutex);
}

这里我们为防止多个线程去访问同一个dataArray属性,在resetStatue方法中使用了互斥锁,但是resetStatue的调用是在互斥锁初始化(pthread_mutex_init(&(_mutex), NULL))之前,这样的调用顺序是错误的,在不开启TSan时,程序不会发生崩溃。开启Tasn后,效果如下:

屏幕快照 2017-03-26 下午7.33.48.png

左边runtime issue中明确的告诉了我们错误的类型(Use of uninitialized mutexes),而且把线程中的历史信息都记录了下来以便我们分析并解决这个问题。

在开发中我们还会用到Reveal、Charles、Instruments的Leaks、Time Profiler等工具,掌握这些后会让你在开发中发现问题、解决问题更加容易,提高生产力。

上一篇下一篇

猜你喜欢

热点阅读