GeoFirestore for iOS — 使用 Firestore 进行实时位置查询
GeoFirestore 是一个基于 Swift 的开源库,允许您基于地理位置存储和查询一系列文档。
GeoFirestore 的核心功能是简单地存储带有字符串键的位置。然而,其主要优势在于能够实时查询给定地理区域内的文档。
GeoFirestore 使用 Firestore 数据库进行数据存储,允许查询结果在数据更改时实时更新。GeoFirestore 仅选择性地加载特定位置的附近数据,即使数据集非常大,也能保持应用程序轻量和响应。
将 GeoFirestore 集成到您的数据中
GeoFirestore 被设计成一个轻量级的 Firestore 扩展。但是,为了保持简单,GeoFirestore 在 Firestore 数据库中以其自己的格式和位置存储数据。这使得您现有的数据格式和安全规则保持不变,您可以将 GeoFirestore 作为一种简单易用的地理查询解决方案添加,而无需修改现有数据。
示例使用
假设你正在构建一个用来评分酒吧的应用程序,并将酒吧的所有信息(例如:名称、营业时间和价格范围)存储在 collection(bars).document(bar-id)
中。之后,你想为用户提供搜索附近酒吧的功能。这就需要用到 GeoFirestore。你可以使用 GeoFirestore 存储每个酒吧文档的位置信息,GeoFirestore 使得你能够轻松地查询附近的酒吧。
示例
要运行示例项目,首先从仓库克隆项目,然后从 Example 目录中运行 pod install
。
在 iOS 中下载 GeoFirestore
如果你使用的是 CocoaPods,请将以下内容添加到你的 Podfile 中
pod ‘Geofirestore'
开始使用 Firestore
GeoFirestore 需要使用 Firestore 数据库来存储位置数据。你可以在 这里了解更多关于 Firestore 的信息。
使用 GeoFirestore
GeoFirestore
使用 GeoFirestore
对象来读取和写入 Firestore 数据库中的地理位置数据以及创建查询。为了创建一个新的 GeoFirestore
实例,需要将其附加到一个 Firestore 收藏引用上
let geoFirestoreRef = Firestore.firestore().collection("my-collection")
let geoFirestore = GeoFirestore(collectionRef: geoFirestoreRef)
设置位置数据
要设置一个文档的位置,只需调用 setLocation
方法。
geoFirestore.setLocation(location: CLLocation(latitude: 37.7853889, longitude: -122.4056973), forDocumentWithID: "que8B9fxxjcvbC81h32VRjeBSUW2") { (error) in
if (error != nil) {
print("An error occured: \(error)")
} else {
print("Saved location successfully!")
}
}
或者使用 GeoPoint
设置位置。
geoFirestore.setLocation(geopoint: GeoPoint(latitude: 37.7853889, longitude: -122.4056973), forDocumentWithID: "que8B9fxxjcvbC81h32VRjeBSUW2") { (error) in
if (error != nil) {
print("An error occured: \(error)")
} else {
print("Saved location successfully!")
}
}
要删除位置并从数据库中删除位置,只需调用
geoFirestore.removeLocation(forDocumentWithID: "que8B9fxxjcvbC81h32VRjeBSUW2")
检索位置
检索位置是通过回调实现的。如果文档不在 GeoFirestore 中,回调将被调用并传回 nil
。如果发生错误,回调将传回错误,位置将是 nil
。
geoFirestore.getLocation(forDocumentWithID: "que8B9fxxjcvbC81h32VRjeBSUW2") { (location: CLLocation?, error) in
if (error != nil) {
print("An error occurred: \(error)")
} else if (location != nil) {
print("Location: [\(location!.coordinate.latitude), \(location!.coordinate.longitude)]")
} else {
print("GeoFirestore does not contain a location for this document")
}
}
或者将位置作为 GeoPoint
获取。
geoFirestore.getLocation(forDocumentWithID: "que8B9fxxjcvbC81h32VRjeBSUW2") { (location: GeoPoint?, error) in
if (error != nil) {
print("An error occurred: \(error)")
} else if (location != nil) {
print("Location: [\(location!.latitude), \(location!.longitude)]")
} else {
print("GeoFirestore does not contain a location for this document")
}
}
GeoFirestore 查询
GeoFirestore 允许您使用 GFSQuery
对象查询地理区域内的所有文档。随着文档位置的变化,查询会实时更新,并触发事件通知您是否有任何相关文档移动。GFSQuery
参数以后可以更新以更改查询区域的范围和中心。
// Query using CLLocation
let center = CLLocation(latitude: 37.7832889, longitude: -122.4056973)
// Query locations at [37.7832889, -122.4056973] with a radius of 600 meters
var circleQuery = geoFirestore.query(withCenter: center, radius: 0.6)
// Query using GeoPoint
let center2 = GeoPoint(latitude: 37.7832889, longitude: -122.4056973)
// Query locations at [37.7832889, -122.4056973] with a radius of 600 meters
var circleQuery2 = geoFirestore.query(withCenter: center2, radius: 0.6)
// Query location by region
let span = MKCoordinateSpanMake(0.001, 0.001)
let region = MKCoordinateRegionMake(center.coordinate, span)
var regionQuery = geoFirestore.query(inRegion: region)
接收地理查询事件
可能与地理查询发生三种类型的事件
- 文档进入:一个文档的位置现在符合查询标准。
- 文档退出:一个文档的位置不再符合查询标准。
- 文档移动:一个文档的位置发生了变化,但仍然符合查询标准。
对于符合查询的所有文档,以及任何后来进入查询的文档,将会触发文档进入事件。文档移动和文档退出事件将保证在文档进入事件之前触发。
要观察地理查询的事件,您可以使用 observe:with:
注册一个回调。
let queryHandle = query.observe(.documentEntered, with: { (key, location) in
print("The document with documentID '\(key)' entered the search area and is at location '\(location)'")
})
要取消一个或所有地理查询的回调,分别调用 removeObserver:withHandle:
或 removeAllObservers:
。
等待查询“就绪”
有时您想了解当所有初始文档的数据已从服务器加载,并且相应的事件被这些文档触发时。例如,您可能想在数据完全加载后隐藏加载动画。GFSQuery
提供了一个方法来监听这些就绪事件
query.observeReady {
print("All initial data has been loaded and events have been fired!")
}
注意,在初始加载数据时位置可能会改变,因此文档移动和文档退出事件可能仍然会在就绪事件触发之前发生。
当查询条件更新时,现有的位置将被重新查询,并且一旦触发更新查询的所有事件,就绪事件将被再次触发。这包括不再符合查询的文档的文档退出事件。
更新查询条件
要更新查询条件,您可以在 GFSQuery
对象上使用 center
和 radius
属性。对于在旧检索区域和新检索区域之间移动的文档,将分别触发文档退出和文档进入事件。由于查询条件发生变化,不会触发文档移动事件;然而,文档移动事件可能独立发生。
方便的扩展
为了便于在 GeoPoint
和 CLLocation
之间转换,我们提供了一些有用的扩展
let cllocation = CLLocation(latitude: 37.7832889, longitude: -122.4056973)
let geopoint = GeoPoint(latitude: 37.7832889, longitude: -122.4056973)
// Converting from CLLocation to Geopoint
let loc1: GeoPoint = cllocation.geopointValue()
let loc2: GeoPoint = GeoPoint.geopointWithLocation(location: cllocation)
// Converting from Geopoint to CLLocation
let loc3: CLLocation = geopoint.locationValue()
let loc4: CLLocation = CLLocation.locationWithGeopoint(geopoint: geopoint)
API参考与文档
完整的API参考和文档在此处可用:点击 here
许可证
GeoFirestore可在MIT许可证下使用。更多信息请参阅LICENSE文件。
版权所有 © 2018 Imperium Labs