iOS Swift-使用NSTimer为应用程序后台重新加载位置功能不起作用 [英] iOS Swift - Reload location function with NSTimer for app background doesn't work

查看:102
本文介绍了iOS Swift-使用NSTimer为应用程序后台重新加载位置功能不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在定位服务方面遇到了问题.我无法设置通过NSTimer在后台更新我的位置坐标的函数.这是我来自appDelegate的代码:

I've got a problem with location services. I can't set up a function that updates my location coordinates in the background by a NSTimer. Here is my code from appDelegate:

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()

}

PS. -当然,我已经导入了corelocation. -当我重新进入该应用程序时,控制台将打印本应在后台打印的内容.

PS. - Of course that i've imported corelocation. - When I get back into the app, the console prints what should have printed in the background.

推荐答案

在后台运行应用程序时,无法使NSTimer像这样工作. NSTimer不是实时机制".从

You can not make an NSTimer work like this while your application is in the background. NSTimer's are not "real-time mechanisms". From the official documentation:

计时器与运行循环配合使用.要有效使用计时器,您应该了解运行循环的工作方式-请参阅

Timers work in conjunction with run loops. To use a timer effectively, you should be aware of how run loops operate—see NSRunLoop and Threading Programming Guide. 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.

计时器不是实时机制;它不是实时机制.仅当已添加计时器的运行循环模式之一正在运行并且能够检查计时器的触发时间是否经过时,它才会触发.由于典型的运行循环管理着各种输入源,因此计时器时间间隔的有效分辨率被限制在50到100毫秒的数量级. 如果计时器的触发时间发生在长时间的调用期间,或者当运行循环处于不监视计时器的模式下时,计时器将不启动,直到运行循环下次检查计时器时为止.因此,计时器可能实际触发的时间可能是在计划的触发时间之后的相当长的一段时间.

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.

强调我的想法.

重要的是,当应用程序在后台运行时,计时器原本计划在其上的任何运行循环都不会处于活动状态.

The important take away from this is that while your application is in the background, any run loop that your timer would have been scheduled on is not actively running.

一旦您的应用返回到前台,此运行循环就会触发,看到您的计时器已过期,并将消息发送到选择器.

As soon as your app returns to the foreground, this run loop fires back up, sees that your timer is overdue, and sends the message to the selector.

在iOS 7及更高版本中,如果您想在后台执行操作,则可以告诉OS您要执行后台获取".

With iOS 7 and forward, if you want to perform operations in the background, you can tell the OS that you want to perform "background fetches".

要进行设置,我们必须首先告诉OS我们要多久获取一次数据,因此在didFinishLaunching...中,添加以下方法:

To set this up, we must first tell the OS how frequently we want to fetch data, so in didFinishLaunching..., add the following method:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    application.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
    return true
}

我们可以在此处传递任何时间间隔(例如,如果我们只想每天检查一次).但是,我们传入的值仅定义了两次检查之间应该经过的最短时间.无法告知操作系统两次检查之间的最长时间.

We can pass any time interval here (for example, if we only want to check once a day). The value we pass in is only defining a minimum amount of time that should pass between checks, however. There is no way to tell the OS a maximum amount of time between checks.

现在,我们必须实现当操作系统为我们提供机会进行后台工作时实际调用的方法:

Now, we must implement the method that actually gets called when the OS gives us an opportunity to do background work:

func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
    // do background work
}

在此方法中,我们可以做任何我们想做的.但是有两个问题.

We can do whatever we want within this method. There are two catches, however.

  1. 在我们的应用程序在后台运行时调用此方法.操作系统将我们限制为(我相信)三十秒.三十秒后,我们的时间到了.
  2. 我们必须打电话给completionHandler()(否则操作系统会认为我们花了所有的时间).
  1. This method is called while our app is in the background. The OS limits us to (I believe) thirty seconds. After thirty seconds, our time is up.
  2. We must call the completionHandler() (or the OS will think we used all of our time).

传入的completionHandler带有一个枚举UIBackgroundFetchResult.我们应该根据实际结果将其传递给.Failed.NewData.NoData(此方法通常通常用于检查服务器中的新数据).

The completionHandler that gets passed in takes an enum, UIBackgroundFetchResult. We should pass it either .Failed, .NewData, or .NoData, depending upon what our actual results were (this approach is typically used for checking a server for fresh data).

因此,我们的方法可能如下所示:

So, our method might look like this:

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)
    }
}

请记住,对于操作系统实际让我们在后台运行此代码的频率,我们拥有绝对 zero 的控制权.操作系统使用多种指标来优化用户体验.

Keep in mind, we have absolutely zero control over how frequently the OS will actually let us run this code in the background. The OS uses several metrics in order to optimize the user's experience.

认为,如果您的应用向完成处理程序报告.Failed,则操作系统可能会很快给您第二次机会,但是如果您滥用.Failed,则操作系统可能会将您的黑名单列入黑名单应用程序使用后台抓取功能(Apple 可以拒绝您的应用程序).

I think if your app reports .Failed to the completion handler, the OS might give you a second chance soon, however if you're abusing .Failed, the OS could probably blacklist your application from using background fetches (and Apple could deny your app).

如果您的应用程序未报告.NewData,则操作系统将使您的应用程序执行后台工作的频率降低.我之所以这样说并不是因为我建议您始终只报告.NewData.您绝对应该准确地报告.该操作系统在计划工作方面非常聪明.如果在没有新数据的情况下通过.NewData,则操作系统将使您的应用更频繁地工作,这可能会更快耗尽用户的电池(并可能导致他们完全卸载您的应用).

If your app isn't reporting .NewData, the OS will let your app do background work less often. I'm not saying this because I recommend that you just always report .NewData. You should definitely report accurately. The OS is very smart about scheduling work. If you're passing .NewData when there isn't new data, the OS will let your app work more often than it may need to, which will drain the user's battery quicker (and may lead to them uninstalling your app altogether).

但是,您的应用何时进行后台工作还涉及其他指标.在用户正在积极使用其设备的情况下,操作系统不太可能让任何应用程序进行后台工作,而在用户不使用其设备的情况下,操作系统更可能会让应用程序进行后台工作.此外,在WiFi上以及插入某种充电器时,操作系统更有可能进行后台工作.

There are other metrics involved in when your app gets to do background work however. The OS is very unlikely to let any app do background work while the user is actively using their device, and it is more likely to let apps do background work while the user is not using their device. Additionally, OS is more likely to do background work while it is on WiFi and while it is plugged into a charger of some sort.

操作系统还将查看用户如何定期使用您的应用程序,或何时何时使用您的应用程序.如果用户每天下午6点使用您的应用,而从未在其他任何时间使用,则您的应用很可能总是有机会在下午5:30到下午6点之间(就在用户使用该应用之前)进行后台工作,并且在一天中的其他任何时间从不.如果用户很少使用您的应用,则可能需要几天,几周或几个月才能在后台工作.

The OS will also look at how regularly the user uses your app, or when they regularly use it. If the user uses your app every day at 6pm, and never at any other time, it's most likely that your app will always get an opportunity to do background work between 5:30pm and 6pm (just before the user will use the app) and never during any other part of the day. If the user very rarely uses your app, it may be days, weeks, or months between opportunities to work in the background.

这篇关于iOS Swift-使用NSTimer为应用程序后台重新加载位置功能不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆