Swift:didExitRegion 延迟会导致错过信标事件



我正在监视定义为信标区域 1 的两个信标 1 (房间 1( 和信标区域 2 (房间 2(, 我正在记录每个进入和退出事件 (因为我们想计算在房间内花费的时间(.

我在记录出口方面遇到了挑战,因为didExitRegion火灾时会发生轻微的延迟。

真实世界:

时间 0:00(分钟:秒(:人员进入房间 1。

时间10:00:人员离开1号房间。

时间10:15:人员进入2号房间。

时间20:00:人员离开2号房间。

Swift/iOS World:

时间 0:00: 人进入房间 1, 进入区域火灾信标区域 1 (房间 1(

时间10:00:人员离开1号房间。蟋蟀鸣叫。

时间 10:15: 人进入房间 2, 确实进入区域火灾信标区域 2 (房间 2(

时间 10:30: 确实退出区域迟来的信标区域 1 (房间 1(

时间 20:00 人退出会议室 2,但未检测到退出,因为出口 1 延迟了 ~30 秒,因此在触发会议室 2 进入后以编程方式发生。

简而言之,延迟允许第二个入口先于第一个出口,因此第二个出口永远不会触发。

我知道didExitRegion延迟是不可避免的。 我很好奇是否有解决方法可以捕获此示例中的第二个出口,也许是通过延迟 didEnterRegion 触发以允许第一个出口"赶上",或者也许通过为每个信标区域运行单独的 didEnter 和 didExit 函数? Swift 似乎有意强迫我使用CLRegionCLBeaconRegion作为区域:didEnterRegiondidExitRegion的参数。

代码示例:

let beaconRegion1 = CLBeaconRegion(uuid: UUID(uuidString: "...")!, major: 12345, minor: 12345, identifier: "Room1")
let beaconRegion2 = CLBeaconRegion(uuid: UUID(uuidString: "...")!, major: 23456, minor: 23456, identifier: "Room2")
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways {
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
startScanning()
}
}
}
func startScanning() {
locationManager?.startMonitoring(for: beaconRegion1)
locationManager?.startMonitoring(for: beaconRegion2)
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
guard region is CLBeaconRegion else {return}
print("Enter: (region.identifer)")
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
guard region is CLBeaconRegion else {return}
print("Exit: (region.identifer)")
}

正如您自己所说,区域退出之前的延迟是不可避免的。 iOS 检测区域出口的方式是,自上次检测到信标数据包以来已经过去了 ~20 秒。

您的计算机程序的工作是使这些信标事件适应有意义的现实世界事件.有无数种方法可以做到这一点,哪些解决方案是合适的,完全取决于您尝试用程序解决的现实世界事件("用例"(。

根据您的描述,听起来您想知道用户何时将手机从一个房间移动到另一个房间。 有很多方法可以做到这一点,哪一种最好取决于我们系统的"要求"——房间相距多远? 用户从一个房间移动到另一个房间的速度有多快? 信标放置在房间内的什么位置? 你能同时看到两个房间的两个信标吗?解决用例所需的正确算法取决于特定要求。

两个想法:

  1. 如果房间相距较远且信标可见性不会重叠:忽略区域出口。 根据上次发生的区域条目确定您所在的房间。 如果你曾经得到一个区域出口,你的程序认为它已经所在的房间,那么你的程序应该确定它根本不在任何房间。

  2. 如果房间足够近,信标可见性重叠: 根本不要使用信标监控. 相反,请使用信标测距, 它为您提供每秒更新一次,其中包含所有可见信标的列表以及以米为单位的估计距离 (信标.accuracy(. 您所在的房间由哪个信标最近决定. 使用此方法时, 您可能还希望向最近的信标确定添加一些"去抖动",以防止与距离估计上的噪声来回反弹. 一个简单的"去抖动"算法是要求第二个信标至少 10% 比当前跟踪的房间信标近,然后才能被认为是最近的. 您可以调整此百分比,以便在弹跳和时间延迟之间获得最佳权衡,以确定下一个房间。

根据@Paulw11和@davidgyoung的回复进行简化和解决。 谢谢。 如果我使用单个didDetermineState而不是单独的didEnterRegiondidExitRegion方法,则无论进入和退出事件的顺序如何,它都会正确跟踪每个区域的所有进入和退出事件。

func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
guard region is CLBeaconRegion else {return}
print("Event detected: (state.rawValue) for (region.identifier)")

对于像我这样的其他快速新手来说,请注意:state.rawValue这里返回 0 表示未知,1 表示内部区域,2 表示外部区域。region.identifier返回标识符字符串(在我的例子中,是 Room1 或 Room2,因为我正在监视两个信标区域。

最新更新