用户位置更新后触发的功能

时间:2019-05-19 02:00:06

标签: ios swift callback location closures

重要说明:我知道我可以简单地在PIL内调用我的getpixel()函数并实现我想要的功能。不幸的是,由于该项目中已经存在一些预先存在的设计决策(我对此没有影响),因此无法采用此路线。

我需要编写一个函数,该函数在用户的坐标更新第一次时触发,然后将这些坐标传递给完成处理程序。就我而言,该完成处理程序是一个名为callback的函数,该函数返回与给定的didUpdateLocations对应的国家/地区。

换句话说,我想编写一个类似于fetchCountry(fromLocation: CLLocation)的函数,能够在收到这些更新后调用完成处理程序:

CLLocation

简而言之,didUpdateLocations只是func getUserLocation(callback: @escaping (CLLocation?) -> Void) { // wait until user's location has been retrieved by location manager, somehow // prepare output for callback function and pass it as its argument let latitude = manager.location!.coordinate.latitude let longitude = manager.location!.coordinate.longitude let location = CLLocation(latitude: latitude, longitude: longitude) callback(location) } 的包装器,但是我真的不确定如何编写此函数以实现我想要的功能。

我在这里的更大目标是,仅在用户启动应用程序时在某国家(例如美国)向其显示本地通知。对我的应用程序来说,很难在 AppDelegate.swift 中做出是否计划此通知的决定,但是只有在检索到用户的位置后才能做出此决定。我打算像这样在appDelegate中使用getUserLocation

我希望我已经清楚地传达了我正在寻求使用带有补全处理程序的函数来实现这一目标。这是我想在 AppDelegate.swift 中执行的代码(即我的用例):

didUpdateLocations

4 个答案:

答案 0 :(得分:2)

编辑了整个答案。您将需要使用同步api(OperationQueueDispatchQueue等),因为甚至在调用CLLocationManager之前,您的getUserLocation就已经在获取。单靠回调无法解决这个问题,这就是为什么我已经删除了该选项的原因。在这种情况下,我使用DispatchQueue是因为我更喜欢使用class LocationManager: NSObject, CLLocationManagerDelegate{ static let shared: LocationManager() private let privateQueue = DispatchQueue.init("somePrivateQueue") private var latestLocation: CLLocation!{ didSet{ privateQueue.resume() } } func getUserLocation(queue: DispatchQueue, callback: @escaping (CLLocation?) -> Void) { if latestLocation == nil{ privateQueue.suspend() //pause queue. wait until got a location } privateQueue.async{ //enqueue work. should run when latestLocation != nil queue.async{ //use a defined queue. most likely mainQueue callback(self.latestLocation) //optionally clear self.latestLocation to ensure next call to this method will wait for new user location. But if you are okay with a cached userLocation, then no need to clear. } } } func fetchCountry(from currentLocation: CLLocation, completion: ) //you already have this right? @objc func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){ latestLocation = locations.last! //API states that it is guaranteed to always have a value } }

/Users/username/Desktop/Directory/Projects/ProjectName/

如果可能,我也同意使用第三方库。这些代码将保证可以进行单元测试和处理边缘情况。而我上面的代码可能有一个错误(我不知道btw)

答案 1 :(得分:1)

从您的AppDelegate代码中,我可以假定您仅在LocationManager类中确定国家/地区。我建议从getUserLocation()函数中删除回调,并在AppDelegate中创建另一个名为postLocalNotification()的函数以仅发布本地通知。

开始获取用户位置时,将调用didUpdateLocation,您应在其中调用具有最新位置的fetchCountry()。如果获取的国家/地区正确,并且您要发布本地通知,请获取appelegate对象,然后调用函数,该函数将按以下方式发布通知

.site-nav {
position:relative;
left:0;
width:100%
)

.site-nav {
position:fixed;
left:0;
width:100%
)

希望这会有所帮助。

答案 2 :(得分:1)

您尝试使用PromiseKit+CoreLocation吗?

它提供CLLocationManager.requestLocation(authorizationType:satisfying:)。如果您不想导入所有PromiseKit framework(这很好,并且避免使用这种完成链),则可以复制its code。他们完全满足您的要求:将CoreLocation请求包装在函数中。

答案 3 :(得分:1)

我不知道您的特殊要求,所以这是一般建议。

听起来您应该设置第二个位置管理器以供自己使用。在应用程序委托中进行设置,并将其委托回调放置在其中,与主位置管理器分开。

请勿尝试延迟willFinishLaunchingWithOptions完成。根据您的要求,在确定国家/地区后,您可能必须将任何UI设置代码移至您自己的回调中以设置界面。我什至会考虑在执行此位置和通知设置时显示不同的UI,然后在您具有通知权限,位置许可和国家/地区后将其换为主UI。

请注意,您通过didUpdateLocations获得的第一个位置更新可能不准确。检查其距离精度,但同时也检查其timestamp并丢弃所有旧的更新。就您的目的(国家/地区准确性)而言,这可能意味着一个小时以上。您实际上只是在考虑用例,该用例是在用户从另一个国家/地区起飞的飞机下机后首次打开您的应用程序。为了准确起见,如果时间戳记是最近的,则对于该级别,3000m或5000m以下的值都可以。

由于所需的精度太低,因此位置将来自蜂窝塔三角测量。它应该很快(也许在2-5秒之内)。

我要注意的一件事是,当主位置管理器执行相同操作时,您的位置管理器将必须请求位置权限。我不知道两次这样的请求权限如何工作。

我还要从通知权限中分开提取国家/地区和获取位置。

一些更一般的建议:您的用例看起来像是在Advanced NSOperations的WWDC会话中处理的。演讲者会处理在下一部分继续进行之前需要设置几项内容的情况。还有一个位置用例和一个权限用例,一个取决于另一个。