XCode启动参数和环境变量
Posted 黄文臣
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XCode启动参数和环境变量相关的知识,希望对你有一定的参考价值。
前言
最近在写《ios代码调试》系列的博客,估计会有十篇以上的内容,等到都写完了会在Github以一个仓库的形式开源出来,欢迎关注我的Github:
这一部分介绍XCode中Argument/Options模块,通过这两个模块,我们可以在启动App的时候传递一些额外的参数进去,覆盖系统的默认值,从而实现特定场景的调试。
Options
Options这里的内容相对简单,但是却容易被忽略。
- Core Location用来模拟App的位置
- Application Data 可以用于测试CoreData的Scheme迁移
- Routing App Coverage File 一个GeoJSON文件,对于导航类应用指明App支持的区域
- Background fetch 表示启动由backgroud fetch触发
- Show non-localized strings 显示没有本地话的字符串
- Application Language & Application Region 系统的语言和区域
Argument Passed On Launch
启动参数用来覆盖NSUserDefaults中的默认值。
注意:启动参数只有在通过XCode启动App的时候才会起作用,直接点击图标启动是没用的。
语言
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
当然,也可以通过Options中的图形化界面来设置语言:
本地化
当你的App需要同时支持多语言的时候,本地化变得很重要。同样的文字,可能在某一中语言中会显示的很长,这时候你可以先通过NSDoubleLocalizedStrings
来看看你的UI在双倍显示当前字符串的时候的样子:
-NSDoubleLocalizedStrings YES
对比下开启前后的效果
当你完成了本地化,你想知道那些字符串没有被本地化
-NSShowNonLocalizedStrings YES
开启这个参数,运行项目,对于没有本地话的字符串,会打印出log,并且在英文环境下,没有被本地话的字符串会变成全部是大写的:
2018-06-09 17:16:23.899756+0800 LaunchArgumentDemo[1592:42786] [strings] ERROR: FlZ-Ch-fUI.text not found in table Main of bundle CFBundle 0x7ffd464002e0 …/Bundle/Application/43466A60-F706-4CCE-A3D5-064C05CD04C6/LaunchArgumentDemo.app> (executable, loaded)
这里有个小技巧,如果是xib/storyboard中的视图,需要通过源代码查看的方式去找到问题: 右键Storyboard -> Open As -> Source Code。接着查找log中提到的id:
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Leo'Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FlZ-Ch-fUI">
<rect key="frame" x="278" y="626.5" width="77" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
Core Data
当你使用Core Data作为本地持久化存储的技术栈时,你会发现很难对程序进行跟踪,这时候可以使用启动参数
log等级分为1到3,越高越详细
-com.apple.CoreData.SQLDebug 3
Log如下
CoreData: sql: pragma cache_size=1000
CoreData: sql: SELECT ...
还有Core Data迁移调试
-com.apple.CoreData.MigrationDebug
Environment Variable
对比启动参数,环境变量的作用域更广一些,它更像是App的全局变量,在应用内任何地方都可以访问到。
可以通过以下方式在代码里获取环境变量
[[NSProcessInfo processInfo] environment]
dyld
优化过App启动时间的同学都知道,启动时间分为main前和main后,XCode可以通过环境变量来打印main函数前的几个过程
- 这部分如果不了解,可以参考我之前的这篇文章《深入理解App的启动过程》
常用的有两个环境变量
DYLD_PRINT_STATISTICS
DYLD_PRINT_STATISTICS_DETAILS
比如,开启DYLD_PRINT_STATISTICS
,
再运行应用,会发现log打印,然后你就知道哪里拖慢了你的应用启动:
Total pre-main time: 823.29 milliseconds (100.0%)
dylib loading time: 226.83 milliseconds (27.5%)
rebase/binding time: 391.41 milliseconds (47.5%)
ObjC setup time: 72.95 milliseconds (8.8%)
initializer time: 131.81 milliseconds (16.0%)
slowest intializers :
libSystem.dylib : 12.17 milliseconds (1.4%)
Foundation : 45.39 milliseconds (5.5%)
libMainThreadChecker.dylib : 74.21 milliseconds (9.0%)
除此之外,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,这样僵尸对象的内存会被释放调。
MallocDebug
内存相关的bug是很难调试的,幸运的是XCode为我们提供了一系列工具,这组工具就是malloc debug。
环境变量对应的功能如下:
MallocStackLogging
记录下来内存分配的调用栈,配合memory debugging等其他可以获取到对象内存地址的debug技巧,可以很容易的查看到一个对象是如何被创建的
- MallocStackLoggingNoCompact的log粒度比MallocStackLogging更细一些,功能上类似
MallocScribble
对于释放的内存,每个Byte填充成0x55,能够提高野指针的crash率。
原理:以OC对象为例,对象被释放后,内存被标记为回收,但是在第二次写入前,内存还是之前的OC对象;这就导致了即使对象被释放了,只有内存被覆盖后的野指针访问才会crash。
对于开发者来说:野指针的crash很有可能是在对象被释放一段时间后,给调试带来了难度,而MallocScribble会在内存释放后,强制覆盖内存,提高野指针的crash率。
MallocGuardEdges
在分配大内存的时候,在内存前后添加额外的页,进行内存保护。
这个环境变量用处比较少,起码我写了这么久的代码,还没有遇到过MallocGuardEdges帮我找到的内存问题。
MallocGuard
开启Malloc Guard后,在调试的时候会使用libgmalloc替换malloc,从而在当内存出现错误的时候,及时crash你的App。
可以通过以下环境变量来开启MallocGuard
DYLD_INSERT_LIBRARIES /usr/lib/libgmalloc.dylib
举例:
int * array = malloc(sizeof(int) * 10);
for (int index = 0; index < 20; index ++)
array[index] = index;
在不开启malloc guard的时候,会crash在main函数,并不会提供有用的信息,在开启malloc guard后:
自定义
除了系统的启动参数和环境变量之外,也支持自定义参数。
我们都知道NSUserDefaults可以用来存储用户的配置信息,比如有一个配置信息是AllowCellularNetwork
,即是否允许蜂窝移动网络下访问网络,这时候就可以测试在用户不同设置的情况下启动:
当开发一个framework的时候,可以利用环境变量来开启一些debug功能,这样能保证线上环境不受影响。
然后,在代码里读取
NSDictionary * environments = [[NSProcessInfo processInfo] environment];
BOOL logOn = [[environments objectForKey:@"Network_Log_Enabled"] isEqualToString:@"YES"];
资料
以上是关于XCode启动参数和环境变量的主要内容,如果未能解决你的问题,请参考以下文章