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

构建测试平台

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

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 并不是所有警告。这一个警告组开启的是编译器开发者对于“你所写的代码中有问题”这一命题有着很高的自信的那些警告。要是在这一组设定下你的代码出现了警告,那基本上就是你的代码真的存在严重问题了。但是同时,并不是说打开Wall就万事大吉了,因为Wall所针对的仅仅只是经典代码库中的为数不多的问题,因此有一些致命的警告并不能被其捕捉到。但是不论如何,因为Wall的警告提供的都是可信度和优先级很高的警告,所以为所有项目(至少是所有新项目)打开这组警告,应该成为一种良好的习惯。

  • -Wextra 如其所名,-Wextra组提供“额外的”警告。这个组和-Wall组几乎一样有用,但是有些情况下对于代码相对过于严苛。一个很常见的例子是,-Wextra中包含了-Wsign-compare, 这个警告标识会开启比较时候对signed和unsigned的类型检查,当比较符两边一边是signed一边是unsigned时,产生警告。其实很多 代码并没有特别在意这样的比较,而且绝大多数时候,比较signed和unsigned也是没有太大问题的(当然不排除会有致命错误出现的情况)。需要注意,-Wextra和-Wall是相互独立的两个警告组,虽然里面打开的警告标识有个别是重复的,但是两组并没有包含的关系。想要同时使用的话必须都加上

  • -Weverything 这个是真正的所有警告。但是一般开发者不会选择使用这个标识,因为它包含了那些还正在开发中的可能尚存bug的警告提示。这个标识一般是编译器开发者用来调试时使用的,如果你想在自己的项目里开启的话,警告一定会爆棚导致你想开始撞墙..

这里推荐-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。

  • Localizability 其实说的是静态分析能够检测出本地化信息缺失的问题,目前能够检测出来两种类型的错误,一种是没有使用 NSLocalizeString这样的API,而直接给控件设置Sting的情况,一种是使用了相应的API,但在comment信息里面赋值为nil。默认是不开启的,在BuildSting中作如下设置:
屏幕快照 2017-03-26 下午1.46.12.png
  • Instance Cleanup 在MRC的代码中,尤其在dealloc中,我们不应该对assign类型的属性进行release操作,应该对retain或者 copy类型的属性进行release操作,如果不这样操作的话,会引发一些不必要的麻烦

  • Nullability 在2015年的WWDC大会上,Objective-C引入的一个新特性就叫做Nullability,用于表明一个东西到底可以为nil还是不可以为nil,这和Swift里的option类型很相似。

Sanitizer和动态分析

  • 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能检查以下类型的错误:

  • Use after free
  • Heap buffer overflow
  • Stack buffer overflow
  • Global variable overflow
  • Overflows in C++ containers
  • Use after return
- (void)viewDidLoad {
    [super viewDidLoad];
    
    char *buffer = malloc(10);
    buffer[10] = 'A';
    free(buffer);
}

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

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

  • Thread Sanitizer (TSan)是Xcode8的新特性,检测线程方面的问题。

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

  • 线程方面的 bug 对时间很敏感, 这就导致很多线程的 bug 极难复现, 复现都成问题, 还怎么改 bug
  • 由于线程的抽象概念导致在 debug 时候也比一般的 debug 更费劲儿, 这时候总觉自己脑子不够使
  • 有时候, 由于线程引起的 crash 或者 error ,让我们根本意识不到这其实是线程出了问题

在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作为一个能够检查线程错误的工具, 它能检查以下类型的错误:

  • Use of uninitialized mutexes(使用未初始化的互斥器)
  • Thread leaks (missing phread_johin)(线程泄漏)
  • Unsafe calls in signal handlers (ex:malloc)()
  • Unlock from wrong thread(从错误的线程解锁)
  • Data race(数据冲突)

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

- (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等工具,掌握这些后会让你在开发中发现问题、解决问题更加容易,提高生产力。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容