GeoFire for iOS — 与 Firebase 实时查询位置
GeoFire 是一个适用于 iOS 的开源库,允许您根据地理位置存储和查询一组键。
在本质上,GeoFire 简单地用字符串键存储位置。然而,其主要优点是可以实时查询给定地理区域内键的机会。
GeoFire 使用 Firebase 数据库进行数据存储,使得查询结果可以根据数据更改实时更新。GeoFire 只选择性地加载某些位置附近的 foliage 数据,即使在数据集极大时也能保持您的应用程序轻量和响应。
Java 和 JavaScript 也提供兼容的 GeoFire 客户端。
将 GeoFire 与您的数据集成
GeoFire是一个轻量级的Firebase附加组件。但是,为了简化问题,GeoFire以自己的格式和位置在你的Firebase数据库中存储数据。这允许你的现有数据格式和安全性规则保持不变,并且你可以方便地将GeoFire作为现有的数据查询解决方案添加,而无需修改现有数据。
示例用法
假设你正在开发一个酒吧评分应用,你将所有关于酒吧的信息(例如名字、营业时间和价格范围)存储在 /bars/<bar-id>
中。后来,你想添加用户在附近搜索酒吧的功能。这就是GeoFire发挥作用的场合。你可以使用GeoFire存储每个酒吧的位置,使用酒吧ID作为GeoFire键。然后GeoFire允许你轻松地查询哪些酒吧ID(键)在附近。要显示关于酒吧的任何额外信息,可以在 /bars/<bar-id>
加载查询返回的每个酒吧的信息。
升级GeoFire
从GeoFire 1.x升级到2.x
随着Firebase在2016年Google I/O的扩展,我们为其添加了许多新特性,并更改了初始化方式,以便更方便地包含它们。有关安装和初始化Firebase SDK的更多信息,请参阅我们的设置说明。
从GeoFire 1.0.x升级到1.1.x
随着GeoFire for iOS 1.1.0的发布,这个库现在使用了Firebase 2.0.0中的新查询功能。因此,您需要升级到Firebase 2.x.x,并在安全规则和Firebase规则中添加新的.indexOn
规则以获得最佳性能。您可以在此处查看更新后的规则,并阅读我们关于数据索引的文档获取更多信息。
下载GeoFire for iOS
如果您正在使用CocoaPods,请在您的Podfile
中添加以下内容
pod 'GeoFire', '~> 4.0'
使用Swift与GeoFire配合使用
GeoFire完全支持Swift!要使用CocoaPods中的GeoFire和Swift,请像以下这样在您的Podfile
中添加use_frameworks!
行
use_frameworks!
pod 'GeoFire', '~> 4.0'
开始使用Firebase
GeoFire使用Firebase实时数据库来存储位置数据。您可以在此处注册免费账号。
GeoFire for iOS 快速入门
参见 examples/SFVehicles
文件夹以获取使用 GeoFire 通过 CocoaPods 的项目的一个工作例子。
GeoFire
使用 GeoFire
对象读取和写入 Firebase 数据库中的地理位置数据,以及创建查询。要创建一个新的 GeoFire
实例,需要将其附加到 Firebase 数据库引用
Objective-C
FIRDatabaseRef *geofireRef = [[FIRDatabase database] reference];
GeoFire *geoFire = [[GeoFire alloc] initWithFirebaseRef:geofireRef];
Swift
let geofireRef = Database.database().reference()
let geoFire = GeoFire(firebaseRef: geofireRef)
请注意,您可以将引用指向 Firebase 数据库中的任何位置,但别忘了为 GeoFire 设置安全规则。
设置位置数据
在GeoFire中,您可以通过字符串键设置和查询位置。要为键设置一个位置,只需调用setLocation:forKey
方法。
Objective-C
[geoFire setLocation:[[CLLocation alloc] initWithLatitude:37.7853889 longitude:-122.4056973]
forKey:@"firebase-hq"];
Swift
geoFire.setLocation(CLLocation(latitude: 37.7853889, longitude: -122.4056973), forKey: "firebase-hq")
或者,可以传递一个回调,在服务器成功保存位置后调用。
Objective-C
[geoFire setLocation:[[CLLocation alloc] initWithLatitude:37.7853889 longitude:-122.4056973]
forKey:@"firebase-hq"
withCompletionBlock:^(NSError *error) {
if (error != nil) {
NSLog(@"An error occurred: %@", error);
} else {
NSLog(@"Saved location successfully!");
}
}];
Swift
geoFire.setLocation(CLLocation(latitude: 37.7853889, longitude: -122.4056973), forKey: "firebase-hq") { (error) in
if (error != nil) {
print("An error occured: \(error)")
} else {
print("Saved location successfully!")
}
}
要删除位置并从数据库中删除位置,可以调用
Objective-C
[geoFire removeKey:@"firebase-hq"];
Swift
geoFire.removeKey("firebase-hq")
获取位置
获取位置使用回调进行。如果关键信息不在GeoFire中,则回调将使用nil
调用。如果发生错误,回调将传递错误并使位置nil
。
Objective-C
[geoFire getLocationForKey:@"firebase-hq" withCallback:^(CLLocation *location, NSError *error) {
if (error != nil) {
NSLog(@"An error occurred getting the location for \"firebase-hq\": %@", [error localizedDescription]);
} else if (location != nil) {
NSLog(@"Location for \"firebase-hq\" is [%f, %f]",
location.coordinate.latitude,
location.coordinate.longitude);
} else {
NSLog(@"GeoFire does not contain a location for \"firebase-hq\"");
}
}];
Swift
geoFire.getLocationForKey("firebase-hq") { (location, error) in
if (error != nil) {
print("An error occurred getting the location for \"firebase-hq\": \(error.localizedDescription)")
} else if (location != nil) {
print("Location for \"firebase-hq\" is [\(location.coordinate.latitude), \(location.coordinate.longitude)]")
} else {
print("GeoFire does not contain a location for \"firebase-hq\"")
}
}
地理查询
GeoFire允许您使用GFQuery
对象在地理区域中查询所有键。随着键的位置变化,查询会实时更新并触发事件,告诉您是否有任何相关的键已移动。GFQuery
参数以后可以更新以更改查询区域的大小和中心。
Objective-C
CLLocation *center = [[CLLocation alloc] initWithLatitude:37.7832889 longitude:-122.4056973];
// Query locations at [37.7832889, -122.4056973] with a radius of 600 meters
GFCircleQuery *circleQuery = [geoFire queryAtLocation:center withRadius:0.6];
// Query location by region
MKCoordinateSpan span = MKCoordinateSpanMake(0.001, 0.001);
MKCoordinateRegion region = MKCoordinateRegionMake(center.coordinate, span);
GFRegionQuery *regionQuery = [geoFire queryWithRegion:region];
Swift
let center = CLLocation(latitude: 37.7832889, longitude: -122.4056973)
// Query locations at [37.7832889, -122.4056973] with a radius of 600 meters
var circleQuery = geoFire.queryAtLocation(center, withRadius: 0.6)
// Query location by region
let span = MKCoordinateSpanMake(0.001, 0.001)
let region = MKCoordinateRegionMake(center.coordinate, span)
var regionQuery = geoFire.queryWithRegion(region)
为地球查询接收事件
地球查询可能出现三种事件
- 键入:键的位置现在符合查询标准。
- 键退出:键的位置不再符合查询标准。
- 键移动:键的位置发生变化,但仍然符合查询标准。
对于所有最初匹配查询以及在任何键进入查询的时间都将会触发键入事件。键移动和键退出事件一定会先于键入事件发生。
要观察地球查询的事件,您可以使用observeEventType:withBlock:
注册一个回调。
Objective-C
FIRDatabaseHandle queryHandle = [query observeEventType:GFEventTypeKeyEntered withBlock:^(NSString *key, CLLocation *location) {
NSLog(@"Key '%@' entered the search area and is at location '%@'", key, location);
}];
Swift
var queryHandle = query.observeEventType(.KeyEntered, withBlock: { (key: String!, location: CLLocation!) in
print("Key '\(key)' entered the search area and is at location '\(location)'")
})
为了取消一个或所有地理查询的回调,请分别调用removeObserverWithFirebaseHandle:
或removeAllObservers:
。
等待查询“准备好”
有时您想知道所有初始键的数据何时已从服务器加载,并且相应的键事件已触发。例如,您可能希望在数据全部加载后隐藏加载动画。GFQuery
提供了一种方法来监听这些就绪事件
Objective-C
[query observeReadyWithBlock:^{
NSLog(@"All initial data has been loaded and events have been fired!");
}];
Swift
query.observeReadyWithBlock({
print("All initial data has been loaded and events have been fired!")
})
请注意,在初始加载数据期间,位置可能会更改,因此可能仍然会在就绪事件触发之前发生键移动和键退出的事件。
当更新查询标准时,现有位置将进行重新查询,并且在所有更新查询的事件(包括不再与查询匹配的键的键退出的事件)发动完毕后,将再次触发就绪事件。
更新查询条件
要更新查询条件,您可以在 GFQuery
对象上使用 center
和 radius
属性。当按键从旧搜索区域移动到新搜索区域时,将触发退出键和键入事件。由于查询条件更改,不会触发按键移动事件;然而,按键移动事件可能会独立发生。
部署
- 使用
git pull
更新主分支 - 标记并推送此版本的标签
- 使用
./build.sh
构建二进制文件 - 从已经获得 Firebase CocoaPods 权限的 Macbook 上,执行
pod trunk push
- 使用此版本的变更日志更新 firebase-versions
- 将编译的
target/GeoFire.framework.zip
添加到版本中
贡献
如果您想为 GeoFire for iOS 贡献,您需要运行以下命令来设置环境:
$ git clone https://github.com/firebase/geofire-objc.git
$ cd geofire-objc
$ pod install
$ open Geofire.xcworkspace