in iOS ~ read.

Xcode Build Settings - Preprocessing

编译器标识

  • 编译器标识被用来在编译时定义常量,可以针对你的代码编译配置做一些 tricky 的事情。
  • 有三个地方可以设置这些

    • OTHER_CFLAGS (Other C Flags)
    • GCC_PREPROCESSOR_DEFINITIONS (Preprocessor Macros)
    • INFOPLIST_PREPROCESSOR_DEFINITIONS (Info.plist Preprocessor Definitions)
  • Other C Flags 的设置和其他两个预处理设置的区别是它的值会被直接传递给编译器。这意味着如果你想定义一个叫 "A1" 的常量,你可以设置一个 C Flag -DA1,它将被原样传递给编译器,并且将定义A1常量。然而,这样潜在的风险是一个错误的 C 标识位设置将会潜在增加你的编译时间。

  • 另一方面,通过预处理器设置 -D 传入的任何内容都将被自动传递给编译器。就像上面说的 A1 参数那样设置。这意味着如果一旦写了一个错误的标识,也会得到一个格式错误的返回结果。因此,我坚持使用预处理器宏在定义编译器标志时候来设置,将其他 C 标识的设置保留到真的希望直接将标识传递给编译器的时候。
  • 编译器标识即可以像 (A=1)这样定义,也可以像常量那样定义(A)。常量定义方式本质上是 boolean 值,有或者没有。值定义有值,但是真的不希望编译器通过复杂的条件来生成您的代码。如果想使用值定义,请坚持将标志设置为1,并简单地检查它是否存在。
  • 如何使用?最常见的用法是基于构建配置动态地交换代码。一旦你设置了标识位,你可以对你的代码做一些灵活动态的编译。举例说明:
#if RELEASE
static NSString *const MY_API_URI = @"https://api.example.com/";  
#else
static NSString *const MY_API_URI = @"https://api.staging-example.com/";  
#endif
  • 还记得 "Info.plist" 预处理定义么?这些可以与 INFOPLIST_PREPROCESS (预处理 Info.plist 文件)结合使用打到动态编辑 Info.plist 文件的效果。这项技术最常的使用场景是替换你的包唯一标识和修改产品名称,这样你就能区分 beta 编译和 release 编译了,并能够保持两个在同一时间安装。右键点击 Info.plist 文件,并且选择 OpenAs -> Source Code,你可以看到 plist 文件的原始 XML 文件格式。找到要修改的部分,并且使用前面使用的编译器条件语句。
<key>CFBundleDisplayName</key>  
#if RELEASE
<string>${PRODUCT_NAME}</string>  
#else
<string>${PRODUCT_NAME} Beta</string>  
#endif
<key>CFBundleIdentifier</key>  
#if RELEASE
<string>com.yourcompany.myapp-appstore</string>  
#else
<string>com.yourcompany.myapp-beta</string>  
#endif
  • 一旦开始在 Info.plist 文件中添加编译器条件语句,Xcode 将会告诉你文件已经损坏不可读。不要担心,并不是这样的。你可以同样 点击右键 -> Open As -> Source Code源代码来添加编译器条件,这可能导致的一个问题是,新版本的 Xcode 中 Summary无法读取 Info.plist 信息。这意味着,如果想更改文件中包含的任何设置,就必须直接编辑 XML,这并不总是愉快的体验。

  • 实际上,可以使用一些内置的标志来帮助动态编译源代码。对于我们而言,最有趣的是 TARGET_IPHONE_SIMULATORTARGET_OS_IPHONE。它们是作为值定义,因此,应该使用 #if 检查条件,而不是 #ifdef。这里有很多又去的地方。我最喜欢的用例是前面的动态 API 常量的扩展。在为 rails 应用程序开发 API 时(我可以访问源代码),我更喜欢在本地运行应用程序,而不是处理对登台服务器的调用。所以我用上面的例子,像这样修改它:

#if TARGET_IPHONE_SIMULATOR
static NSString *const MY_API_URI = @"http://localhost:3000/";  
#elif RELEASE
static NSString *const MY_API_URI = @"https://api.example.com/";  
#else
static NSString *const MY_API_URI = @"https://api.staging-example.com/";  
#endif
  • 现在,当你通过模拟器编译的时候,我会将 app 指向本地的 Rails 服务。但是 app 仍旧会在 release 编译时指向真正的 API,节省很大的时间开销。

  • 除此之外,有许多变量可以被用来在编译器标记来动态创建标识。值得注意的是,CONFIGURATION 变量对应于构建配置名。这意味着为所有编译设置一个CONFIGURATION_$(CONFIGURATION)预处理宏,就可以在 Debug 下使用 CONFIGURATION_Debug 编译设置,Release 下使用 CONFIGURATION_Release

comments powered by Disqus