如何在iOS应用程序中每隔n分钟更新一次后台位置?

我正在寻找一种方法来在iOS应用程序中每隔n分钟更新一次后台位置。 我正在使用iOS 4.3,该解决scheme应该适用于非越狱的iPhone。

我试过/考虑了以下选项:

  • CLLocationManager startUpdatingLocation/startMonitoringSignificantLocationChanges :根据configuration的属性,它可以在后台运行,但似乎无法强制它每n分钟更新一次位置
  • NSTimer :当应用程序在前台运行时工作,但似乎没有为后台任务devise
  • 本地通知:本地通知可以每n分钟计划一次,但不可能执行一些代码来获取当前位置(用户不必通过通知启动应用程序)。 这种方法似乎也不是一个干净的方法,因为这不是应该使用的通知。
  • UIApplication:beginBackgroundTaskWithExpirationHandler :据我所知,当应用程序移动到后台而不是实现“长时间运行”的后台进程时,这应该用于在后台完成一些工作(也受到时间的限制)。

我怎样才能实现这些定期的背景位置更新?

我find了一个解决scheme来实现这个在苹果开发者论坛的帮助下:

  • 指定location background mode
  • UIApplication:beginBackgroundTaskWithExpirationHandler:在后台创build一个NSTimer UIApplication:beginBackgroundTaskWithExpirationHandler:
  • n 小于 UIApplication:backgroundTimeRemaining ,它将工作得很好。 当n 较大时location manager应该在没有剩余时间之前再次启用(和禁用),以避免后台任务被终止。

这是有效的,因为位置是三种允许的后台执行types之一

注意:我在模拟器中testing失败了一些时间,但是它不起作用。 但是,它在我的手机上正常工作。

iOS 8/9/10上 ,每5分钟更新一次后台位置,请执行以下操作:

  1. 转到项目 – >function – >背景模式 – >select位置更新

  2. 转到项目 – >信息 – >添加一个NSLocationAlwaysUsageDescription与空值(或可选的任何文本)

  3. 当你的应用程序在后台进行位置工作,并发送坐标到Web服务或每5分钟做任何事情,像下面的代码中实现它。

我没有使用任何后台任务或计时器。 我已经用iOS 8.1的设备testing了这个代码,这个设备在我的桌子上躺了几个小时,我的应用程序在后台运行。 设备被locking,并且代码始终正常运行。

 @interface LocationManager () <CLLocationManagerDelegate> @property (strong, nonatomic) CLLocationManager *locationManager; @property (strong, nonatomic) NSDate *lastTimestamp; @end @implementation LocationManager + (instancetype)sharedInstance { static id sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[self alloc] init]; LocationManager *instance = sharedInstance; instance.locationManager = [CLLocationManager new]; instance.locationManager.delegate = instance; instance.locationManager.desiredAccuracy = kCLLocationAccuracyBest; // you can use kCLLocationAccuracyHundredMeters to get better battery life instance.locationManager.pausesLocationUpdatesAutomatically = NO; // this is important }); return sharedInstance; } - (void)startUpdatingLocation { CLAuthorizationStatus status = [CLLocationManager authorizationStatus]; if (status == kCLAuthorizationStatusDenied) { NSLog(@"Location services are disabled in settings."); } else { // for iOS 8 if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { [self.locationManager requestAlwaysAuthorization]; } // for iOS 9 if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) { [self.locationManager setAllowsBackgroundLocationUpdates:YES]; } [self.locationManager startUpdatingLocation]; } } - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { CLLocation *mostRecentLocation = locations.lastObject; NSLog(@"Current location: %@ %@", @(mostRecentLocation.coordinate.latitude), @(mostRecentLocation.coordinate.longitude)); NSDate *now = [NSDate date]; NSTimeInterval interval = self.lastTimestamp ? [now timeIntervalSinceDate:self.lastTimestamp] : 0; if (!self.lastTimestamp || interval >= 5 * 60) { self.lastTimestamp = now; NSLog(@"Sending current location to web service."); } } @end 

我在一个正在开发的应用程序中做了这个。 当应用程序在后台,但定时器不工作,但应用程序不断收到位置更新。 我在文档中的某个地方看过(我现在似乎无法find它,当我这样做的时候我会发布一个更新),只有在应用程序在后台时才能在主动运行循环中调用一个方法。 应用程序代表甚至在bg中也有一个活动的运行循环,所以你不需要创build自己的工作。 [我不知道这是否是正确的解释,但那是我从我读到的理解]

首先,在应用程序的info.plist中添加键UIBackgroundModeslocation对象。 现在,您需要做的是在应用程序的任何位置启动位置更新:

  CLLocationManager locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self;//or whatever class you have for managing location [locationManager startUpdatingLocation]; 

接下来,编写一个方法来处理位置更新,在应用程序委托中说-(void)didUpdateToLocation:(CLLocation*)location 。 然后在您启动位置pipe理器的类(因为我们将位置pipe理器委托设置为“self”)中实现了方法locationManager:didUpdateLocation:fromLocationCLLocationManagerDelegate 。 在这个方法里面,你需要检查你必须处理位置更新的时间间隔是否已经过去。 您可以通过每次保存当前时间来做到这一点。 如果时间已过,请从您的应用程序委托中调用UpdateLocation方法:

 NSDate *newLocationTimestamp = newLocation.timestamp; NSDate *lastLocationUpdateTiemstamp; int locationUpdateInterval = 300;//5 mins NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; if (userDefaults) { lastLocationUpdateTiemstamp = [userDefaults objectForKey:kLastLocationUpdateTimestamp]; if (!([newLocationTimestamp timeIntervalSinceDate:lastLocationUpdateTiemstamp] < locationUpdateInterval)) { //NSLog(@"New Location: %@", newLocation); [(AppDelegate*)[UIApplication sharedApplication].delegate didUpdateToLocation:newLocation]; [userDefaults setObject:newLocationTimestamp forKey:kLastLocationUpdateTimestamp]; } } } 

即使您的应用程序在后台,这也会每5分钟调用一次您的方法。 Imp:这个实现消耗电池,如果你的位置数据的准确性不重要,你应该使用[locationManager startMonitoringSignificantLocationChanges]

在将其添加到您的应用程序之前,请阅读位置感知编程指南

现在,iOS6是最好的方式有一个永远运行的位置服务是…

 - (void)applicationWillResignActive:(UIApplication *)application { /* Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. */ NSLog(@"to background"); app.isInBackground = TRUE; UIApplication *app = [UIApplication sharedApplication]; // Request permission to run in the background. Provide an // expiration handler in case the task runs long. NSAssert(bgTask == UIBackgroundTaskInvalid, nil); bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ // Synchronize the cleanup call on the main thread in case // the task actually finishes at around the same time. dispatch_async(dispatch_get_main_queue(), ^{ if (bgTask != UIBackgroundTaskInvalid) { [app endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; } }); }]; // Start the long-running task and return immediately. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Do the work associated with the task. locationManager.distanceFilter = 100; locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; [locationManager startMonitoringSignificantLocationChanges]; [locationManager startUpdatingLocation]; NSLog(@"App staus: applicationDidEnterBackground"); // Synchronize the cleanup call on the main thread in case // the expiration handler is fired at the same time. dispatch_async(dispatch_get_main_queue(), ^{ if (bgTask != UIBackgroundTaskInvalid) { [app endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; } }); }); NSLog(@"backgroundTimeRemaining: %.0f", [[UIApplication sharedApplication] backgroundTimeRemaining]); } 

就这样testing一下:

我开始了应用程序,去背景,并在几分钟内在车上移动。 然后,我回家1小时,并开始再次移动(不开放的应用程序)。 地点再次启动。 然后停了两个小时,又开始了。 一切都OK了…

不要忘记使用iOS6中的新位置服务

 - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { CLLocation *loc = [locations lastObject]; // Lat/Lon float latitudeMe = loc.coordinate.latitude; float longitudeMe = loc.coordinate.longitude; } 

让别人有噩梦找出这一个。 我有一个简单的解决scheme。

  1. 从raywenderlich.com看这个例子 – >有示例代码,这个工作完美,但不幸的是在后台位置没有计时器。 这将无限期地运行。
  2. 添加计时器使用:

     -(void)applicationDidEnterBackground { [self.locationManager stopUpdatingLocation]; UIApplication* app = [UIApplication sharedApplication]; bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ [app endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; self.timer = [NSTimer scheduledTimerWithTimeInterval:intervalBackgroundUpdate target:self.locationManager selector:@selector(startUpdatingLocation) userInfo:nil repeats:YES]; } 
  3. 只要不要忘记在info.plist中添加“位置更新的应用程序寄存器”。

不幸的是,你所有的假设看起来都是正确的,我不认为有办法做到这一点。 为了节省电池寿命,iPhone的位置服务是基于移动的。 如果手机坐在一个地方,它对位置服务是不可见的。

CLLocationManager将只能调用locationManager:didUpdateToLocation:fromLocation:当手机收到一个位置更新,这只有在三个位置服务之一(蜂窝塔,gps,wifi)感知到一个改变时才会发生。

其他一些可能有助于进一步解决问题的事情:

  • 启动和停止服务会导致didUpdateToLocation委托方法被调用,但newLocation可能有一个旧的时间戳。

  • 地区监测可能有帮助

  • 在后台运行时,请注意可能很难获得Apple批准的“完整”LocationServices支持。 根据我所见,他们专门devise了startMonitoringSignificantLocationChanges作为需要后台定位支持的应用程序的低功耗替代scheme,并强烈鼓励开发人员使用此function,除非应用程序绝对需要它。

祝你好运!

更新:这些想法可能已经过时了。 看起来好像人们正在用上面的@wjans回答成功。

我确实使用定位服务编写了一个应用程序,应用程序必须每隔10秒发送一次。 它工作得很好。

只需使用Apple的文档中的“ allowDeferredLocationUpdatesUntilTraveled:timeout ”方法即可。

我做的是:

必需:注册后台模式更新位置。

1.创buildLocationMangerstartUpdatingLocation ,并根据需要accuracyfilteredDistance startUpdatingLocation

 -(void) initLocationManager { // Create the manager object self.locationManager = [[[CLLocationManager alloc] init] autorelease]; _locationManager.delegate = self; // This is the most important property to set for the manager. It ultimately determines how the manager will // attempt to acquire location and thus, the amount of power that will be consumed. _locationManager.desiredAccuracy = 45; _locationManager.distanceFilter = 100; // Once configured, the location manager must be "started". [_locationManager startUpdatingLocation]; } 

2.要使应用程序在后台使用allowDeferredLocationUpdatesUntilTraveled:timeout方法永远运行,您必须在应用移至后台时使用新参数重新启动allowDeferredLocationUpdatesUntilTraveled:timeout ,如下所示:

 - (void)applicationWillResignActive:(UIApplication *)application { _isBackgroundMode = YES; [_locationManager stopUpdatingLocation]; [_locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; [_locationManager setDistanceFilter:kCLDistanceFilterNone]; _locationManager.pausesLocationUpdatesAutomatically = NO; _locationManager.activityType = CLActivityTypeAutomotiveNavigation; [_locationManager startUpdatingLocation]; } 

3.应用程序正常使用locationManager:didUpdateLocations:获取updatedLocations locationManager:didUpdateLocations: callback:

 -(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { // store data CLLocation *newLocation = [locations lastObject]; self.userLocation = newLocation; //tell the centralManager that you want to deferred this updatedLocation if (_isBackgroundMode && !_deferringUpdates) { _deferringUpdates = YES; [self.locationManager allowDeferredLocationUpdatesUntilTraveled:CLLocationDistanceMax timeout:10]; } } 

但是你应该在locationManager:didFinishDeferredUpdatesWithError:处理数据locationManager:didFinishDeferredUpdatesWithError:为你的目的callback

 - (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error { _deferringUpdates = NO; //do something } 

5. 注意:我想我们应该重置LocationManager参数,每次应用程序切换后台/地面模式。

 if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) { [self.locationManager setAllowsBackgroundLocationUpdates:YES]; } 

这是自iOS 9以来的背景位置跟踪所必需的。

这是我使用的:

 import Foundation import CoreLocation import UIKit class BackgroundLocationManager :NSObject, CLLocationManagerDelegate { static let instance = BackgroundLocationManager() static let BACKGROUND_TIMER = 150.0 // restart location manager every 150 seconds static let UPDATE_SERVER_INTERVAL = 60 * 60 // 1 hour - once every 1 hour send location to server let locationManager = CLLocationManager() var timer:NSTimer? var currentBgTaskId : UIBackgroundTaskIdentifier? var lastLocationDate : NSDate = NSDate() private override init(){ super.init() locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyKilometer locationManager.activityType = .Other; locationManager.distanceFilter = kCLDistanceFilterNone; if #available(iOS 9, *){ locationManager.allowsBackgroundLocationUpdates = true } NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.applicationEnterBackground), name: UIApplicationDidEnterBackgroundNotification, object: nil) } func applicationEnterBackground(){ FileLogger.log("applicationEnterBackground") start() } func start(){ if(CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedAlways){ if #available(iOS 9, *){ locationManager.requestLocation() } else { locationManager.startUpdatingLocation() } } else { locationManager.requestAlwaysAuthorization() } } func restart (){ timer?.invalidate() timer = nil start() } func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) { switch status { case CLAuthorizationStatus.Restricted: //log("Restricted Access to location") case CLAuthorizationStatus.Denied: //log("User denied access to location") case CLAuthorizationStatus.NotDetermined: //log("Status not determined") default: //log("startUpdatintLocation") if #available(iOS 9, *){ locationManager.requestLocation() } else { locationManager.startUpdatingLocation() } } } func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { if(timer==nil){ // The locations array is sorted in chronologically ascending order, so the // last element is the most recent guard let location = locations.last else {return} beginNewBackgroundTask() locationManager.stopUpdatingLocation() let now = NSDate() if(isItTime(now)){ //TODO: Every n minutes do whatever you want with the new location. Like for example sendLocationToServer(location, now:now) } } } func locationManager(manager: CLLocationManager, didFailWithError error: NSError) { CrashReporter.recordError(error) beginNewBackgroundTask() locationManager.stopUpdatingLocation() } func isItTime(now:NSDate) -> Bool { let timePast = now.timeIntervalSinceDate(lastLocationDate) let intervalExceeded = Int(timePast) > BackgroundLocationManager.UPDATE_SERVER_INTERVAL return intervalExceeded; } func sendLocationToServer(location:CLLocation, now:NSDate){ //TODO } func beginNewBackgroundTask(){ var previousTaskId = currentBgTaskId; currentBgTaskId = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({ FileLogger.log("task expired: ") }) if let taskId = previousTaskId{ UIApplication.sharedApplication().endBackgroundTask(taskId) previousTaskId = UIBackgroundTaskInvalid } timer = NSTimer.scheduledTimerWithTimeInterval(BackgroundLocationManager.BACKGROUND_TIMER, target: self, selector: #selector(self.restart),userInfo: nil, repeats: false) } } 

我开始像AppDelegate中的跟踪:

 BackgroundLocationManager.instance.start() 

我使用了xs2bush的获取间隔的方法(使用timeIntervalSinceDate )并在其上进行了一些扩展。 我想确保我获得了我所需要的准确性,并且保持GPS无线电的正常运行。

我继续使用以下设置持续运行位置:

 locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers; locationManager.distanceFilter = 5; 

这是一个相对较低的电池消耗。 当我准备好下一次定期阅读地点时,我首先检查地点是否在我想要的准确度之内,如果是,我就使用这个地点。 如果不是的话,那么我提高这个精度:

 locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; locationManager.distanceFilter = 0; 

得到我的位置,然后一旦我有了位置,我再次把精度降低,以尽量减less电池的消耗。 我已经写了一个完整的工作示例,我也写了服务器端代码来源收集位置数据,将其存储到数据库,并允许用户实时查看GPS数据或检索和查看以前存储的路线。 我有iOS,Android,Windows Phone和Java我的客户端。 所有的客户都是本地编写的,他们都在后台正常工作。 该项目是MIT许可的。

iOS项目针对iOS 6,使用iOS 7的基础SDK。您可以在此处获取代码。

如果您发现任何问题,请在github上提出问题。 谢谢。

看来stopUpdatingLocation是触发后台看门狗定时器,所以我用didUpdateLocationreplace它:

  [self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers]; [self.locationManager setDistanceFilter:99999]; 

这似乎有效地closures了GPS。 后台NSTimer的select器变成:

 - (void) changeAccuracy { [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; [self.locationManager setDistanceFilter:kCLDistanceFilterNone]; } 

All I'm doing is periodically toggling the accuracy to get a high-accuracy coordinate every few minutes and because the locationManager hasn't been stopped, backgroundTimeRemaining stays at its maximum value. This reduced battery consumption from ~10% per hour (with constant kCLLocationAccuracyBest in the background) to ~2% per hour on my device

There is a cocoapod APScheduledLocationManager that allows to get background location updates every n seconds with desired location accuracy.

 let manager = APScheduledLocationManager(delegate: self) manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100) 

The repository also contains an example app written in Swift 3.

Working Code(Entire Stepwise Code)

步骤1

  • Go to project -> Capabilities -> Background Modes -> select Location updates.
  • Go to Project -> Info -> add a key NSLocationAlwaysUsageDescription with an optional string.

第2步

Add this code to AppDelegate.m

 @interface AppDelegate ()<CLLocationManagerDelegate> @property (strong, nonatomic) CLLocationManager *locationManager; @property (strong, nonatomic) NSTimer *timer; @end 

Step 3 Add This Code in to applicationDidEnterBackground method in AppDelegate.m

  - (void)applicationDidEnterBackground:(UIApplication *)application { UIApplication *app = [UIApplication sharedApplication]; __block UIBackgroundTaskIdentifier bgTaskId = [app beginBackgroundTaskWithExpirationHandler:^{ [app endBackgroundTask:bgTaskId]; bgTaskId = UIBackgroundTaskInvalid; }]; dispatch_async( dispatch_get_main_queue(), ^{ self.timer = nil; [self initTimer]; [app endBackgroundTask:bgTaskId]; bgTaskId = UIBackgroundTaskInvalid; }); } - (void)initTimer { if (nil == self.locationManager) self.locationManager = [[CLLocationManager alloc] init]; self.locationManager.delegate = self; [self.locationManager requestAlwaysAuthorization]; [self.locationManager startMonitoringSignificantLocationChanges]; if (self.timer == nil) { self.timer = [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:@selector(checkUpdates:) userInfo:nil repeats:YES]; } } - (void)checkUpdates:(NSTimer *)timer{ UIApplication *app = [UIApplication sharedApplication]; double remaining = app.backgroundTimeRemaining; if(remaining < 580.0) { [self.locationManager startUpdatingLocation]; [self.locationManager stopUpdatingLocation]; [self.locationManager startMonitoringSignificantLocationChanges]; } } - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { NSLog(@"Did Update Location = %f / %f", [newLocation coordinate].latitude, [newLocation coordinate].longitude); [self updateLocationWithLatitude:[newLocation coordinate].latitude andLongitude:[newLocation coordinate].longitude]; UIApplication* app = [UIApplication sharedApplication]; __block UIBackgroundTaskIdentifier bgTask = bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ [app endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self initTimer]; }); } - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { [self.locationManager stopUpdatingLocation]; UIApplication *app = [UIApplication sharedApplication]; __block UIBackgroundTaskIdentifier bgTask = bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ [app endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; [self initTimer]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Do the work associated with the task }); } -(void)updateLocationWithLatitude:(CLLocationDegrees)latitude andLongitude:(CLLocationDegrees)longitude{ //Here you can update your web service or back end with new latitude and longitude } 

Attached is a Swift solution based in:

Define App registers for location updates in the info.plist

Keep the locationManager running all the time

Switch kCLLocationAccuracy between BestForNavigation (for 5 secs to get the location) and ThreeKilometers for the rest of the wait period to avoid battery drainage

This example updates location every 1 min in Foreground and every 15 mins in Background.

The example works fine with Xcode 6 Beta 6, running in a iOS 7 device.

In the App Delegate (mapView is an Optional pointing to the mapView Controller)

 func applicationDidBecomeActive(application: UIApplication!) { if appLaunched! == false { // Reference to mapView used to limit one location update per timer cycle appLaunched = true var appDelegate = UIApplication.sharedApplication().delegate as AppDelegate var window = appDelegate.window var tabBar = window?.rootViewController as UITabBarController var navCon = tabBar.viewControllers[0] as UINavigationController mapView = navCon.topViewController as? MapViewController } self.startInitialPeriodWithTimeInterval(60.0) } func applicationDidEnterBackground(application: UIApplication!) { self.startInitialPeriodWithTimeInterval(15 * 60.0) } func startInitialPeriodWithTimeInterval(timeInterval: NSTimeInterval) { timer?.invalidate() // reset timer locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation timer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: Selector("getFirstLocationUpdate:"), userInfo: timeInterval, repeats: false) } func getFirstLocationUpdate(sender: NSTimer) { let timeInterval = sender.userInfo as Double timer?.invalidate() mapView?.canReportLocation = true timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: Selector("waitForTimer:"), userInfo: timeInterval, repeats: true) } func waitForTimer(sender: NSTimer) { let time = sender.userInfo as Double locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation finalTimer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: Selector("getLocationUpdate"), userInfo: nil, repeats: false) } func getLocationUpdate() { finalTimer?.invalidate() mapView?.canReportLocation = true } 

In the mapView (locationManager points to the object in the AppDelegate)

 override func viewDidLoad() { super.viewDidLoad() var appDelegate = UIApplication.sharedApplication().delegate! as AppDelegate locationManager = appDelegate.locationManager! locationManager.delegate = self canReportLocation = true } func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) { if canReportLocation! { canReportLocation = false locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers } else { //println("Ignore location update") } }