本软件包包含必要的类型和有用的函数,用于为 OpenParking 项目创建数据源。OpenParking 项目专注于收集可用公共停车位的数据,并尽可能以开放数据的形式提供这些数据和衍生信息。
请查看文档以了解 API 的具体信息。
数据源是 Swift 软件包,每个软件包包含一个或多个数据源。如果您尚未设置 Swift,请访问 swift.org 获取有关如何在您的系统上运行 Swift 的说明。
让我们为虚构的城市比勒费尔德创建一个新的数据源。
$ mkdir Bielefeld & cd Bielefeld
$ swift package init
现在打开您新建的软件包清单 (Package.swift
) 并将 OpenParking 添加到您的依赖项列表中,将 latest
替换为上面列出的最新发行版本。
// ...
dependencies: [
.package(url: "https://github.com/OpenParkingApp/OpenParking.git", from: "latest"),
]
// ...
Swift 还要求您将相关的 products 作为依赖项添加到您的 targets 中。OpenParking 包含两个 targets:OpenParking 和 OpenParkingTestSupport,后者包含一些 helpers,用于在您的 test target 中验证您的数据。现在,我们的清单中的 targets 部分如下所示。OpenParkingTestSupport 对 BielefeldTests 的依赖项不幸地要求您更加详细,因为它与软件包基本名称不同。
// ...
targets: [
.target(
name: "Bielefeld",
dependencies: ["OpenParking"]),
.testTarget(
name: "BielefeldTests",
dependencies: [
.product(name: "OpenParkingTestSupport", package: "OpenParking"),
"Bielefeld"
]),
]
// ...
现在让我们进入 Sources/Bielefeld/Bielefeld.swift 中的主要实现。我们将在其中定义实际的数据源以及它如何获取数据。
首先,我们将导入 OpenParking,创建一个新类型并使其符合 Datasource
协议。不要忘记将该类型标记为 public,以便可以从该模块外部访问它。
import Foundation
import OpenParking
public class Bielefeld: Datasource {
}
此时,您的编辑器可能会抱怨 Bielefeld
不符合 Datasource
,因为它需要一些属性。这些是:
此外,该协议要求我们实现函数 func data() throws -> DataPoint
,这是该数据源的用户获取当前数据的入口点。
实现所需的属性和 data()
的占位符后,我们得到以下内容。不要忘记为您的类型添加一个 public 初始化器,以便可以在其他地方创建它。
public class Bielefeld: Datasource {
public let name = "Bielefeld"
public let slug = "bielefeld"
public let infoURL = URL(string: "https://bielefeld.de")!
public init() {}
public func data() throws -> DataPoint {
fatalError("not yet implemented")
}
}
在继续实际实现 data()
之前,让我们快速添加几行必要的代码,以便稍后测试我们的实现。这在 Tests/BielefeldTests/BielefeldTests.swift 中完成。修改该文件,使其如下所示:
import XCTest
import OpenParkingTestSupport
import Bielefeld
final class BielefeldTests: XCTestCase {
func testDatasource() throws {
validate(datasource: Bielefeld())
}
}
就这样! validate(datasource:)
是 OpenParkingTestSupport 中的一个函数,它获取实时数据并运行一些验证以检查它是否合理。
您可以通过 $ swift test
运行测试,您将看到它遇到的任何警告和错误。
这是有趣的部分,但不幸的是,这也是每个数据源都不同的部分。但是,OpenParking 软件包中提供了一些有用的实用程序,可以使它更容易维护。
为了便于使用,有两个同步网络函数:get(url:headers:)
和 post(url:headers:)
,它们都返回类型为 (Data, HTTPURLResponse)
的元组。
此外,String
上还有一些有用的扩展,用于解析日期和转义 HTML 实体。
主要思想是获取当前数据并对其进行处理,以返回包含 Lot
信息的 DataPoint
。有关详细信息,最好查看现有的数据源,例如 Basel 或 Herrenberg。
这里需要注意的另一点是,有三个可用的选项来指示数据的问题。
warn(_:lotName:)
函数。这些警告将被汇总,并(希望)由运行数据导入的人员稍后查看。DataPoint
不是 Lot
的直接集合,而是包含类型为 Result<Lot, LotError>
的值。如果特定 lot 的数据已损坏且无法聚合,则使用 LotError
来突出显示,可能是由于缺少静态元数据或其他原因。data()
的抛出特性并抛出一个合适的错误。所有这些以及更多内容都应在项目的文档中列出。
您可能希望将静态数据与数据源捆绑在一起,包括 lot 坐标、地址、类型以及任何其他未与实时数据一起获取的内容。如果实时数据中不存在,则最好在此处包含可用总空间的计数。这种数据通常以 GeoJSON 文件的形式捆绑在一起。
它看起来像这样:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [8.533417, 52.025246]
},
"properties": {
"name": "Parkplatz Alte Post",
"address": "Friedrich-Ebert-Straße",
"type": "lot",
"total": 80
}
},
// ...
]
}
将此文件与您的软件包捆绑在一起非常容易,只需将该文件(通常名为 geojson.json
)放入我们 target 的源目录中,例如,在本例中为 Sources/Bielefeld
。要实际将我们的静态数据与软件包捆绑在一起,我们必须将资源添加到软件包清单中的 target 中。
.target(
name: "Bielefeld",
dependencies: ["OpenParking"],
resources: [
.process("geojson.json"),
]),
然后,我们可以让框架自动解码它并通过在我们的数据源中执行以下操作来访问其数据。
let geodata = try self.geodata(from: .module)
这将返回一个 GeoJson
对象,我们可以使用它通过诸如 lot(withName:)
之类的函数来检索我们存储的元数据。有关更多信息,请参见项目的文档。