xcode设置欢迎页时间_XCode启动参数和环境变量

6337ac04bf29d1dba0874ad1fdada856.png

作者 | 黄文臣 
来源 | CSDN-Leo的专栏 
时间 | 2018-06-30

前言

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

LeoMobileDeveloper[1]

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

Options

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

fc0479047ca220aa89d9dac0ef4e3afd.png

• 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中的默认值。

e214ae18cd4a4759b468a25d814d3da4.png

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

6702ce8cb573ad41339ac082cac65169.png

本地化

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

-NSDoubleLocalizedStrings YES

对比下开启前后的效果

57adb83ae033434ca74f9a7c7e8b99ab.png

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

-NSShowNonLocalizedStrings YES

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

1dcf7810879c0953b55154ab9c9b0fb6.png

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:

"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"/>key="fontDescription" type="system" pointSize="17"/>key="textColor"/>key="highlightedColor"/>

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的启动过程》[2]
常用的有两个环境变量

DYLD_PRINT_STATISTICS
DYLD_PRINT_STATISTICS_DETAILS

比如,开启DYLD_PRINT_STATISTICS,

6e57c5b7485b364001b2406282e329f6.png

再运行应用,会发现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。

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

f9299d6d32d35a15de0dbdc83dfb1b61.png

MallocStackLogging

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

• MallocStackLoggingNoCompact的log粒度比MallocStackLogging更细一些,功能上类似

5b5542f2b1a942a4d772f38919fe0d9c.png

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后:

47171332b8791b5f8964974b94a4196b.png

自定义

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

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

f53196df8e754aab60faaa87fef6da3f.png

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

1e46b522e998a6bed686c7738fc8b625.png

然后,在代码里读取

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/


推荐阅读
• App 二进制文件重排已经被玩坏了 • 一站式解决WKWebView各类问题 • iOS应用程序瘦身的静态库解决方案 • 基于桥的全量方法Hook方案 - 探究苹果主线程检查实现 • iOS代码瘦身实践:删除无用的类
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值