在 iOS Swift 个应用程序中存储 Global/Environment 个变量

Storing Global/Environment Variables in iOS Swift Apps

我是一名 JavaScript 网络应用程序开发人员,刚刚继承了一个遗留 iOS 应用程序。该应用程序充满了硬编码 URL 指向我们的产品 API.

我想将 Base URL 分解到常量文件、环境变量文件或配置文件中,以便不同的 Base URL 可以在不同的地方使用环境(开发、暂存、生产)。

Swift 地区的最佳做法是什么? 我可以使用类似于 .env 文件的东西吗?

有些人建议为每个环境创建一个配置文件 (.xcconfig),然后您可以在那里设置不同的基础 URL。

在我以前工作的地方,我们使用了一个常量文件,我们在其中根据环境设置不同的值、url、端口等:

#if DEBUG
let a = 2

#if PRODUCTION
let a = 4

我认为这是最好的做法。

与检查代码中的常量和在每个环境中到处乱扔相同变量的不同值相比,我一直做的可能是一种更灵活的方法。

也没有必要创建 .xcconfig 文件。

设置整个东西需要更多的工作,但之后您会发现它非常容易使用。

在我的示例中,您可以看到我如何在 Toeppersee iOS app.

中为 production/UITest/development 构建设置不同的 REST 端点

对您的 Info.plist

的更改

首先,只需定义一个新常量和 select 一个标识您的内容的名称,在我的例子中是 TS_WEBSERVICE_URL 确保将其值设置为您选择的名称,括在 $() 中(方括号,而不是大括号!),在我的例子中是 $(TS_WEBSERVICE_URL).

构建设置

在构建设置选项卡中,添加自定义的“用户定义”构建参数,再次使用相同的名称:

您看到您可以为 Debug、UITests 和 Release 定义值。而且我将这种机制用于环境中的很多不同事物。

添加更多环境

如果您需要更多环境,请将它们添加到您的主项目节点的“信息”选项卡中(就像我在 UITests 中所做的那样):

使用代码中的值

现在开始简单的部分:在代码中使用新定义的值。这一切都归结为获取一个 NSBundle 实例并读取 Info.plist 中定义的值,该值已在构建过程中自动替换。

Objective C:

NSString *webserviceURL = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"TS_WEBSERVICE_URL"];

Swift:

let webserviceURL = Bundle.main.object(forInfoDictionaryKey: "TS_WEBSERVICE_URL") as! String

每个环境设置只需一行代码。

有一件事我没有展示,但也相当简单:只需为 NSBundle 定义一个类别并提供名为 webserviceUrl 的新方法和类似方法。然后可以这样调用它们:Bundle.main.webserviceUrl() 这进一步简化了源代码。

编辑:将扩展写入 Bundle 对象(可选)

为了实现前面提到的对webservice URL的简化访问,创建并调用了一个新的Swift文件(例如):Bundle+AppAdditions.swift

import Foundation

// An extension (or category in Objective C) extends any types functionality,
// in our case the NSBundle foundation class.
extension Bundle {
    // get the webservice URL from an NSBundle instance
    public func webserviceUrl() -> String {
        // get an object for info dictionary key and cast it as string
        return self.object(forInfoDictionaryKey: "TS_WEBSERVICE_URL") as! String
    }
}

扩展直接在任何给定的 Bundle 实例上工作,不一定只在 main 包上工作。示例:

let url = Bundle.main.webserviceUrl()

或任何其他捆绑包,例如对于包含 InitialViewController:

的 App Clip 扩展
let url = Bundle(for: InitialViewController.self).webserviceUrl()

我实际上会添加另一个静态扩展方法来获取 App Clip 扩展包。但这也是可选的 ;-)