XCode启动参数和环境变量

Posted iOS开发

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XCode启动参数和环境变量相关的知识,希望对你有一定的参考价值。

点击右侧关注,了解黑客的世界!

点击右侧关注,掌握进阶之路!

点击右侧关注,探讨技术话题!

作者 | 黄文臣 
来源 | CSDN-Leo的专栏 
时间 | 2018-06-30
来源公众号丨知识小集


前言


最近在写《ios代码调试》系列的博客,估计会有十篇以上的内容,等到都写完了会在Github以一个仓库的形式开源出来,欢迎关注我的Github:

LeoMobileDeveloper[1]

这一部分介绍XCode中Argument/Options模块,通过这两个模块,我们可以在启动App的时候传递一些额外的参数进去,覆盖系统的默认值,从而实现特定场景的调试。

Options


Options这里的内容相对简单,但是却容易被忽略。

XCode启动参数和环境变量

• 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启动参数和环境变量

注意:启动参数只有在通过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中的图形化界面来设置语言:

XCode启动参数和环境变量


本地化


当你的App需要同时支持多语言的时候,本地化变得很重要。同样的文字,可能在某一中语言中会显示的很长,这时候你可以先通过NSDoubleLocalizedStrings来看看你的UI在双倍显示当前字符串的时候的样子:

 
   
   
 
-NSDoubleLocalizedStrings YES

对比下开启前后的效果
XCode启动参数和环境变量

当你完成了本地化,你想知道那些字符串没有被本地化

 
   
   
 
-NSShowNonLocalizedStrings YES


开启这个参数,运行项目,对于没有本地话的字符串,会打印出log,并且在英文环境下,没有被本地话的字符串会变成全部是大写的:


XCode启动参数和环境变量

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: sqlSELECT ...

还有Core Data迁移调试

 
   
   
 
-com.apple.CoreData.MigrationDebug

Environment Variable


对比启动参数,环境变量的作用域更广一些,它更像是App的全局变量,在应用内任何地方都可以访问到。

可以通过以下方式在代码里获取环境变量

 
   
   
 
[[NSProcessInfo processInfo] environment]

dyld


优化过App启动时间的同学都知道,启动时间分为main前和main后,XCode可以通过环境变量来打印main函数前的几个过程

• 这部分如果不了解,可以参考我之前的这篇文章《深入理解App的启动过程》[2]

常用的有两个环境变量

 
   
   
 
DYLD_PRINT_STATISTICS
DYLD_PRINT_STATISTICS_DETAILS

比如,开启DYLD_PRINT_STATISTICS,

XCode启动参数和环境变量

再运行应用,会发现log打印,然后你就知道哪里拖慢了你的应用启动:

 
   
   
 
Total pre-main time823.29 milliseconds (100.0%)
         dylib loading time226.83 milliseconds (27.5%)
        rebase/binding time391.41 milliseconds (47.5%)
            ObjC setup time:  72.95 milliseconds (8.8%)
           initializer time131.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。

环境变量对应的功能如下:

XCode启动参数和环境变量

MallocStackLogging


记录下来内存分配的调用栈,配合memory debugging等其他可以获取到对象内存地址的debug技巧,可以很容易的查看到一个对象是如何被创建的

• MallocStackLoggingNoCompact的log粒度比MallocStackLogging更细一些,功能上类似
XCode启动参数和环境变量


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 = 0index < 20index ++) {
    array[index] = index;
}

在不开启malloc guard的时候,会crash在main函数,并不会提供有用的信息,在开启malloc guard后:

XCode启动参数和环境变量


自定义


除了系统的启动参数和环境变量之外,也支持自定义参数。

我们都知道NSUserDefaults可以用来存储用户的配置信息,比如有一个配置信息是AllowCellularNetwork,即是否允许蜂窝移动网络下访问网络,这时候就可以测试在用户不同设置的情况下启动:

XCode启动参数和环境变量

当开发一个framework的时候,可以利用环境变量来开启一些debug功能,这样能保证线上环境不受影响。

XCode启动参数和环境变量

然后,在代码里读取

 
   
   
 
NSDictionary * environments = [[NSProcessInfo processInfo] environment];
BOOL logOn = [[environments objectForKey:@"Network_Log_Enabled"] isEqualToString:@"YES"];

参考

[1]https://github.com/LeoMobileDeveloper 
[2]https://github.com/LeoMobileDeveloper/Blogs/blob/master/iOS/What%20happened%20at%20startup%20time.md 
[3]https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html 
[4]http://nshipster.cn/launch-arguments-and-environment-variables/


 推荐↓↓↓ 

以上是关于XCode启动参数和环境变量的主要内容,如果未能解决你的问题,请参考以下文章

Xcode中的变量模板(variable template)的用法

Xcode 7 UI 测试目标语言环境和区域设置

Linux bash基础特性二

jupyter 启动时的问题

我正在片段中启动我的活动,但变量变为空?

在 Xcode 构建阶段运行脚本中设置全局环境变量