var locationManager = CLLocationManager() func applicationDidEnterBackground(application: UIApplication) { self.locationManager.delegate = self self.locationManager.desiredAccuracy = kCLLocationAccuracyBest self.theTimer = NSTimer(fireDate: NSDate(),interval: 40,target: self,selector: "handleTimer",userInfo: nil,repeats: true) NSRunLoop.currentRunLoop().addTimer(self.theTimer,forMode: NSDefaultRunLoopMode) } func locationManager(manager: CLLocationManager!,didUpdateLocations locations: [AnyObject]!) { var locValue:CLLocationCoordinate2D = manager.location.coordinate println("dinBack = \(locValue.latitude) \(locValue.longitude)") self.locationManager.stopUpdatingLocation() } func handleTimer(){ println("started") self.locationManager.startUpdatingLocation() }
解决方法
Timers work in conjunction with run loops. To use a timer effectively,you should be aware of how run loops operate—see 07001 and 07002. Note in particular that run loops maintain strong references to their timers,so you don’t have to maintain your own strong reference to a timer after you have added it to a run loop.
A timer is not a real-time mechanism; it fires only when one of the run loop modes to which the timer has been added is running and able to check if the timer’s firing time has passed. Because of the varIoUs input sources a typical run loop manages,the effective resolution of the time interval for a timer is limited to on the order of 50-100 milliseconds. If a timer’s firing time occurs during a long callout or while the run loop is in a mode that is not monitoring the timer,the timer does not fire until the next time the run loop checks the timer. Therefore,the actual time at which the timer fires potentially can be a significant period of time after the scheduled firing time.
强调我的.
重要的是,当您的应用程序在后台时,您的计时器将被安排的任何运行循环都没有正在运行.
一旦您的应用程序返回到前台,此运行循环将重新启动,发现您的计时器已过期,并将该消息发送到选择器.
对于iOS 7和转发,如果要在后台执行操作,可以告诉操作系统您要执行“后台提取”.
要进行此设置,我们必须首先告诉操作系统我们想要获取数据的频率,因此在didFinishLaunching …中,添加以下方法:
func application(application: UIApplication,didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { application.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum) return true }
我们可以在这里传递任何时间间隔(例如,如果我们只想每天检查一次).但是,我们传入的值仅定义了应在检查之间传递的最小时间量.没有办法告诉操作系统检查之间的最长时间.
现在,我们必须实现在操作系统为我们提供后台工作机会时实际调用的方法:
func application(application: UIApplication,performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) { // do background work }
我们可以在这种方法中做任何我们想做的事.然而,有两个渔获量.
>当我们的应用程序在后台时调用此方法.操作系统限制我们(我相信)三十秒.三十秒后,我们的时间到了.
>我们必须调用completionHandler()(或操作系统会认为我们使用了所有时间).
传入的completionHandler采用枚举UIBackgroundFetchResult.我们应该传递.Failed,.NewData或.NoData,具体取决于我们的实际结果(这种方法通常用于检查服务器的新数据).
所以,我们的方法可能如下所示:
func application(application: UIApplication,performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) { // do stuff if let _ = error { completionHandler(.Failed) } else if results.count > 0 { completionHandler(.NewData) } else { completionHandler(.NoData) } }
请记住,我们绝对无法控制操作系统实际让我们在后台运行此代码的频率.操作系统使用多个指标来优化用户体验.
我想如果你的应用程序报告.对于完成处理程序,操作系统可能会很快给你第二次机会,但是如果你滥用.Failed,操作系统可能会将你的应用程序列入黑名单使用后台提取(并且Apple可能会拒绝你的应用程序).
如果您的应用没有报告.NewData,操作系统会让您的应用减少后台工作的频率.我不是这样说的,因为我建议你总是报告.NewData.你一定要准确报道.操作系统在调度工作方面非常聪明.如果您在没有新数据的情况下传递.NewData,操作系统会让您的应用程序更频繁地工作,这会更快地耗尽用户的电池(并可能导致他们完全卸载您的应用程序).
但是,当您的应用开展后台工作时,还会涉及其他指标.当用户积极使用他们的设备时,操作系统不太可能让任何应用程序进行后台工作,并且当用户不使用他们的设备时,它更有可能让应用程序进行后台工作.此外,操作系统更有可能在WiFi上进行后台工作,同时将其插入某种充电器.
操作系统还会查看用户定期使用应用程序的频率,或者定期使用应用程序的时间.如果用户每天下午6点使用您的应用程序,而且从未在任何其他时间使用您的应用程序,那么您的应用程序很可能总是有机会在下午5:30至下午6点(在用户使用该应用程序之前)进行后台工作.从来没有在一天的任何其他部分.如果用户很少使用您的应用,那么在后台工作的机会可能是几天,几周或几个月.