#if在动态环境中工作#endif iOS中的App Environment抽象

2.问题

在谈论包括多个后端和应用程序环境的开发设置时,配置将成为救生员,并且是一种设置和构建满足多种需求的应用程序的好方法。

当我们开始考虑明确设置应用程序环境的主要原因时,就会出现问题。

他们注定会有所不同!

这意味着Alpha版本应该与Beta版本有所不同,并且可以肯定的是, DebugRelease之间存在有意义的区别。 只要与其他API URL或某些资产有关,就可以了。 但是,如果它们提供的实际功能有所不同,则可能适得其反。

我确定您至少看过一次此代码:

  #if调试 
// 做点什么
#其他
//做其他事情
#万一

还算不错。 请记住,在大多数情况下,除非您开始归档或在Release中构建,否则将不检查#else之后的代码。 因此,它已经失去了一些编译时安全性。 考虑到这一点:

  #if调试 
//调试流程
#elseif AlPHA
//被认为是Alpha流程
//但是有一个错字,编译器永远不会突出显示
#elseif测试版
// Beta流
#其他
//应该是Release,对吗?
//除非我们添加了更多配置
//忘了处理它们
#万一

从理论上讲,它可以在代码的许多地方发生。 每个添加/删除配置都可能需要重新访问这些位置,然后重新检查流程。 没有编译器的帮助,代码很快变得难以维护。

另一个主题是单元测试-编写有趣的测试。 我有🙂

3.环境抽象

我在许多不同的项目中都在为这个问题而苦苦挣扎。 不管功能切换的好坏,我经常以类似以下内容结束:

 公共枚举环境:字符串{ 
案例调试
案例测试版
案例发布
 公共静态var当前:环境{ 
#if调试
返回.debug
#elseif测试版
返回.beta
#其他
返回.release
#万一
}
}
  ... 
 切换Environment.current { 
案例.debug:
//流程1
案例.beta:
//流程2
案例.release:
//流程3
}

现在只有一个地方可以维护条件编译。 它是如此简单明了,使其更容易保持理智。

该代码始终作为一个整体进行编译,从而显着提高了编译时的安全性。 如果我们添加/删除环境,则编译器将突出显示主要问题。 该模型可用于表示应用程序环境。 并且可以使用一些常见的样板和环境相关变量来扩展它:

 扩展环境{ 
var名称:字符串{return self.rawValue}
var appVersionNumber:字符串{...}
var appBuildNumber:字符串{...}
var apiUrl:URL {...}
}

最后但并非最不重要的一点是,允许覆盖Environment.current(例如,用于测试,但不仅限于):

 公共枚举环境:字符串{ 
案例调试
案例测试版
案例发布
 公共静态var当前:环境{ 
如果让override = Override.current {
返回覆盖
}
  #if调试 
返回.debug
#elseif测试版
返回.beta
#其他
返回.release
}

struct Override {
静态无功电流:环境?
}
}
  ... 
  Environment.Override.current = .beta 

4.一个小技巧

如果您使用的应用程序具有多个构建配置以及所有的暂存和预生产设置,或者如果您愿意,最终将遇到此问题:

“您好,Andrzej,客户给我们发送了屏幕截图,您能看看吗? 最好,”

没有人知道它是用于Alpha还是Beta,而不是说版本号。 即使将这些数据记录在故障单中,我仍然发现它们不止一次不准确(毕竟测试人员是人,如果他们每天从多个应用程序和多个环境中获取数十个屏幕截图,很容易将它们错配)

如所承诺的,有一个小技巧可以使您的生活更轻松。 考虑以下三个屏幕截图:

您可以发现前两个和第三个之间的差异。 让我为您放大: