App的环境

将散乱的配置包装起来

作者:@nixzhu


这里所说的“环境”并不是操作系统或硬件如内存之类,而是app的依赖基础。

比如,当前的语言、服务器域名、内部缓存的引用,或一些配置信息等。此外,如果你的app有用户系统,那还要包括当前登录的用户。

有了环境,就可以改变它。比如改变服务器域名,简单令其指向localhost就可以得到一个调试环境。从这个意义上讲,一切可配置或可替换的变量都是环境的一部分。

当我们有了这样的概念,我们就可以定义它。将我们所关心的环境做成一个封装,并定义为一个全局变量(这个变量的存放位置可能需要考虑一下)。

  1. struct Environment {
  2. enum Language {
  3. case en
  4. case zh
  5. }
  6. let language: Language
  7. let serverDomain: String
  8. let user: User?
  9. }
  10. var environment = Environment(
  11. language: .zh,
  12. serverDomain: "example.com",
  13. user: nil
  14. )

这只是一个简单的例子,你的app所关心的环境很可能不同,自行增减属性。

根据上面的代码,假如app打开一段时间后,用户进行登录,若成功就可以修改environment,给它一个新的有user的值。

如果你要写测试代码,则可以配置测试环境,如:

  1. let environment = Environment(
  2. language: .en,
  3. serverDomain: "localhost:8080",
  4. user: User(...)
  5. )

甚至于你想给app增加一个测试模式(需要特殊条件触发),以便临时切换环境。那可以定义一个环境栈:

  1. struct AppEnvironment {
  2. private init() {
  3. }
  4. private static var stack: [Environment] = []
  5. static var current: Environment? {
  6. return stack.last
  7. }
  8. static func pushEnvironment(_ environment: Environment) {
  9. stack.append(environment)
  10. }
  11. @discardableResult
  12. static func popEnvironment() -> Environment? {
  13. let last = stack.popLast()
  14. return last
  15. }
  16. }

这样,在进入测试模式时,就将一个测试环境压栈中。当然,对应业务代码里要改为使用AppEnvironment.current替换之前的全局变量。至于UI,你可以直接替换window或者present一个最底层的Container ViewController覆盖当前的UI。当你测试结束,弹出测试环境,UI也对应调整一下即可。

假如你的app支持多用户,用户会不停地的切换账号。有了环境这种概念,是不是也觉得挺好实现呢?


本文属于阅读kickstarter/ios-oss的体会之一(我希望能写成一个系列)。

我之所以想起它,是因为最近我参与开发的一个app:SpaceHub,在处理某些推送时需要实现一种临时切换环境的功能,算得上有实际用上这种经验。这大概是阅读好代码的益处之一,尽管比较功利。


更多文章请见:dev-blog/README

欢迎转载,但请一定注明出处! https://github.com/nixzhu/dev-blog