当我们使用Xcode调试app的时候,会传递一些额外的参数进去,覆盖系统的默认值,从而实现特定场景的调试。主要手段就是配置启动参数和环境变量.
全部的配置分布在Info Arguments options Diagnostics
四个板块中
一 首先Info
板块:
-
build configuration
:构建运行模式
设置运行模式`Debug`还是`Release`
也可以自定义构建环境,但依然区分`Debug`还是`Release`
-
debug process as
: 调试角色
是当前用户发起的调试行为还是root行为
-
launch
:启动时机
`Automatically`:自动启动运行
`Wait for executable to be launched` : app处于等待状态,当点击图标或者收到push notification才会启动。
用于调试app启动前的逻辑
二 首先Arguments
板块: 启动参数&环境变量
启动参数:Argument Passed On Launch
:
配置启动参数 用来覆盖NSUserDefaults中的默认值。启动参数只有在通过XCode启动App的时候才会起作用,直接点击图标启动是没用的
1.AppleLanguages可以用来设置启动的语言
更改语言最直接的方式就是:设置 -> 通用 -> 语言 -> 修改语言,然后重启模拟器,接着重启App,这个过程是很繁琐的。
利用启动参数,这个过程变得非常的直接,比如,设置App在简体中文下启动
-AppleLanguages (zh-Hans)
一些常见的语言列表如下:
English (U.S.) en
English (UK) en-GB
English (Australian) en-AU
English (Indian) en-IN
French fr
Spanish es
Portuguese pt
German de
Italian it
Chinese (Simplified) zh-Hans
Chinese (Traditional) zh-Hant
Japanese ja
Korean ko
Russian ru
2.实现本地化
当你的App需要同时支持多语言的时候,本地化变得很重要。同样的文字,可能在某一中语言中会显示的很长,这时候你可以先通过NSDoubleLocalizedStrings来看看你的UI在双倍显示当前字符串的时候的样子:
-NSDoubleLocalizedStrings YES
检查哪些字符串没有被本地化
-NSShowNonLocalizedStrings YES
开启这个参数,运行项目,对于没有本地话的字符串,会打印出log,并且在英文环境下,没有被本地话的字符串会变成全部是大写的:
输出Core Data跟踪日志
当你使用Core Data作为本地持久化存储的技术栈时,你会发现很难对程序进行跟踪,这时候可以使用启动参数
-com.apple.CoreData.SQLDebug 3
log等级分为1到3,越高越详细
4.Core Data迁移调试
-com.apple.CoreData.MigrationDebug
- 日志语法高亮
想让调试语句更加突出吗? 可以使用如下的颜色混合日志参数
-com.apple.CoreData.SyntaxColoredLogging YES
屏幕快照 2019-10-12 下午4.56.12.png
环境变量: Environment Variable
通过代码获取环境变量
[[NSProcessInfo processInfo] environment]
- DYLD : 优化过App启动时间的同学都知道,启动时间分为main前和main后,XCode可以通过环境变量来打印main函数前的几个过程.
常用的有两个环境变量:
DYLD_PRINT_STATISTICS
DYLD_PRINT_STATISTICS_DETAILS
屏幕快照 2019-10-12 下午5.03.53.png
再运行应用,会发现log打印,然后你就知道哪里拖慢了你的应用启动:
dylib loading time: 26.31 milliseconds (26.5%)
rebase/binding time: 1.03 milliseconds (1.0%)
ObjC setup time: 10.59 milliseconds (10.6%)
initializer time: 61.15 milliseconds (61.6%)
slowest intializers :
libSystem.B.dylib : 5.57 milliseconds (5.6%)
libBacktraceRecording.dylib : 3.18 milliseconds (3.2%)
libMainThreadChecker.dylib : 30.87 milliseconds (31.1%)
ZBank : 34.67 milliseconds (34.9%)
total time: 1.0 seconds (100.0%)
total images loaded: 372 (365 from dyld shared cache)
total segments mapped: 20, into 449 pages with 48 pages pre-fetched
total images loading time: 747.41 milliseconds (73.6%)
total load time in ObjC: 10.59 milliseconds (1.0%)
total debugger pause time: 721.09 milliseconds (71.0%)
total dtrace DOF registration time: 0.10 milliseconds (0.0%)
total rebase fixups: 373,831
total rebase fixups time: 9.04 milliseconds (0.8%)
total binding fixups: 544,195
total binding fixups time: 186.19 milliseconds (18.3%)
total weak binding fixups time: 0.76 milliseconds (0.0%)
total redo shared cached bindings time: 194.97 milliseconds (19.2%)
total bindings lazily fixed up: 0 of 0
total time in initializers and ObjC +load: 61.15 milliseconds (6.0%)
libSystem.B.dylib : 5.57 milliseconds (0.5%)
libBacktraceRecording.dylib : 3.18 milliseconds (0.3%)
libMainThreadChecker.dylib : 30.87 milliseconds (3.0%)
ZBank : 34.67 milliseconds (3.4%)
total symbol trie searches: 1239212
total symbol table binary searches: 0
total images defining weak symbols: 37
total images using weak symbols: 100
除此之外,dyld还有很多可以用来调试的环境变量
DYLD_FRAMEWORK_PATH
DYLD_FALLBACK_FRAMEWORK_PATH
DYLD_VERSIONED_FRAMEWORK_PATH
DYLD_LIBRARY_PATH
DYLD_FALLBACK_LIBRARY_PATH
DYLD_VERSIONED_LIBRARY_PATH
DYLD_PRINT_TO_FILE
DYLD_SHARED_REGION
DYLD_INSERT_LIBRARIES
DYLD_FORCE_FLAT_NAMESPACE
DYLD_IMAGE_SUFFIX
DYLD_PRINT_OPTS
DYLD_PRINT_ENV
DYLD_PRINT_LIBRARIES
DYLD_BIND_AT_LAUNCH
DYLD_DISABLE_DOFS
DYLD_PRINT_APIS
DYLD_PRINT_BINDINGS
DYLD_PRINT_INITIALIZERS
DYLD_PRINT_REBASINGS
DYLD_PRINT_SEGMENTS
DYLD_PRINT_STATISTICS
DYLD_PRINT_DOFS
DYLD_PRINT_RPATHS
DYLD_SHARED_CACHE_DIR
DYLD_SHARED_CACHE_DONT_VALIDATE
- Zombie:
开启Zombie,当对象被释放后,他们仍然在内存里,只不过视图访问僵尸对象会报错,可以用于调试EXC_BAD_ACCESS。
可以通过环境变量NSZombieEnabled来开启
NSZombieEnabled YES
也可以选择NSDeallocateZombies,这样僵尸对象的内存会被释放调。
NSDeallocateZombies YES
屏幕快照 2019-10-12 下午5.25.27.png
- MallocDebug
内存相关的bug是很难调试的,幸运的是XCode为我们提供了一系列工具,这组工具就是malloc debug。
环境变量对应的功能如下:
MallocStackLogging
记录下来内存分配的调用栈,配合memory debugging等其他可以获取到对象内存地址的debug技巧,可以很容易的查看到一个对象是如何被创建的
MallocScribble
对于释放的内存,每个Byte填充成0x55,能够提高野指针的crash率。
原理:
以OC对象为例,对象被释放后,内存被标记为回收,
但是在第二次写入前,内存还是之前的OC对象;
这就导致了即使对象被释放了,
只有内存被覆盖后的野指针访问才会crash。
对于开发者来说:野指针的crash很有可能是在对象被释放一段时间后,给调试带来了难度,而MallocScribble会在内存释放后,强制覆盖内存,提高野指针的crash率。
MallocGuardEdges
在分配大内存的时候,在内存前后添加额外的页,进行内存保护。
MallocGuard
开启Malloc Guard后,在调试的时候会使用libgmalloc替换malloc,从而在当内存出现错误的时候,及时crash你的App。
可以通过以下环境变量来开启MallocGuard:
DYLD_INSERT_LIBRARIES /usr/lib/libgmalloc.dylib
在不开启malloc guard的时候,会crash在main函数,并不会提供有用的信息,在开启malloc guard后:
20180630125300902.png4.自定义环境变量
除了系统的启动参数和环境变量之外,也支持自定义参数。
我们都知道NSUserDefaults可以用来存储用户的配置信息,比如有一个配置信息是AllowCellularNetwork,即是否允许蜂窝移动网络下访问网络,这时候就可以测试在用户不同设置的情况下启动:
20180630125317414.png
当开发一个framework的时候,可以利用环境变量来开启一些debug功能,这样能保证线上环境不受影响。
20180630125336145.png
然后,在代码里读取
NSDictionary * environments = [[NSProcessInfo processInfo] environment];
BOOL logOn = [[environments objectForKey:@"Network_Log_Enabled"] isEqualToString:@"YES"];
三 options
板块:
Core Location用来模拟App的位置
Application Data 可以用于测试CoreData的Scheme迁移
Routing App Coverage File 一个GeoJSON文件,对于导航类应用指明App支持的区域
GPU Frame Capture GPU帧率检测
Background fetch 表示启动由backgroud fetch触发
Show non-localized strings 显示没有本地话的字符串
Application Language & Application Region 系统的语言和区域
options 中的部分配置可以通过配置环境变量来实现
四. Diagnostics (诊断)
板块:
1.Runtime Sanitization
运行时调试选项:
启用运行时检查以检测并避免代码中的错误。
Enable Address Sanitizer
// 跟踪代码中的内存冲突。
Thread Sanitization
审核代码中的线程问题。
undefined behavior sanitizer
可在运行时检测未定义的行为
undefined behavior sanitizer可以在运行时检查未定义的行为。
对性能的影响很小,在Debug配置中平均有20%的CPU开销。
未定义的行为包括:整数溢出,无效的布尔枚举值,被零除等
-
Runtime API Checking
运行时API检查
Main Thread Checker
主线程检查
当使用Xcode调试器运行应用程序时,主线程检查器将自动启用。
从后台线程检测对AppKit,UIKit和其他API的无效使用。
-
Memory Management
内存管理
同环境变量配置的内容交叉,在这里可以更加直观的配置.
开启一些内存管理相关的服务,包括内存涂抹,边缘保护,动态内存分配保护,僵尸对象等等
Malloc Scribble // 内存涂抹 用0xAA填充分配的内存,用0x55填充释放的内存。
Malloc Guard Edges // 内存边缘保护
Guard Malloc // 动态内存分配保护
Zombie Objects // 僵尸对象
Malloc Scribble的基本思想是,在对象被释放后,在对应内存块中填上不可访问的无意义的数据(0x55),那么我们再使用这个对象时,程序将直接Crash
-
Logging
后台日志
malloc stack // malloc堆栈日志
Dynamic Linker API Usage // 记录动态链接器API调用(例如,dlopen)。
Dynamic Linker Loads // 记录加载的动态库
参考链接:https://blog.csdn.net/Hello_Hwc/article/details/80865787
网友评论