你不能做一个NSTimer
当您的应用程序处于后台时,可以像这样工作。NSTimer
不是“实时机制”。来自官方文档 https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/#//apple_ref/occ/clm/NSTimer/scheduledTimerWithTimeInterval:target:selector:userInfo:repeats::
定时器与运行循环结合使用。要有效地使用计时器,您应该了解运行循环的运行方式 - 请参阅NS运行循环 https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSRunLoop_Class/index.html#//apple_ref/occ/cl/NSRunLoop and 线程编程指南 https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/Introduction/Introduction.html#//apple_ref/doc/uid/10000057i。请特别注意,运行循环维护对其计时器的强引用,因此在将计时器添加到运行循环后,您不必维护自己对计时器的强引用。
定时器不是实时机制;仅当已添加计时器的运行循环模式之一正在运行并且能够检查计时器的触发时间是否已过时,它才会触发。由于典型运行循环管理的输入源多种多样,因此定时器时间间隔的有效分辨率被限制在 50-100 毫秒的量级。如果计时器的触发时间发生在长标注期间或者当运行循环处于不监视计时器的模式时,计时器不会触发,直到运行循环下次检查计时器。因此,计时器触发的实际时间可能会比计划的触发时间晚很长一段时间。
Emphasis mine.
重要的是,当您的应用程序处于后台时,您的计时器本来安排的任何运行循环都不会主动运行。
一旦您的应用程序返回前台,此运行循环就会重新启动,发现您的计时器已过期,并将消息发送到选择器。
在 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
}
我们可以做的whatever我们想要在这个方法中。然而,有两个问题。
- 当我们的应用程序在后台时调用此方法。操作系统将我们限制在(我相信)三十秒内。三十秒后,我们的时间到了。
- 我们必须调用
completionHandler()
(否则操作系统会认为我们用了所有的时间)。
The completionHandler
传入的内容需要一个枚举,UIBackgroundFetchResult
。我们应该通过它.Failed
, .NewData
, or .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)
}
}
请记住,我们绝对有zero控制操作系统实际上让我们在后台运行此代码的频率。该操作系统使用多个指标来优化用户体验。
I think如果您的应用程序报告.Failed
到完成处理程序,操作系统可能很快就会给你第二次机会,但是如果你滥用.Failed
,操作系统可能会将您的应用程序列入黑名单,禁止使用后台获取(Applecould拒绝您的应用程序)。
如果您的应用没有报告.NewData
,操作系统将使您的应用程序更少地进行后台工作。我这么说并不是因为我建议你总是报告.NewData
。你绝对应该准确地报告。操作系统在安排工作方面非常智能。如果你路过.NewData
当没有新数据时,操作系统会让您的应用程序比实际需要更频繁地运行,这会更快地耗尽用户的电池(并可能导致他们完全卸载您的应用程序)。
然而,当您的应用程序开始执行后台工作时,还涉及其他指标。当用户正在积极使用其设备时,操作系统不太可能让任何应用程序执行后台工作,并且更有可能在用户不使用其设备时让应用程序执行后台工作。此外,操作系统更有可能在连接 WiFi 和插入某种充电器时执行后台工作。
操作系统还会查看用户使用您的应用程序的频率,或者他们经常使用它的时间。如果用户每天下午 6 点使用您的应用程序,并且从不在任何其他时间使用您的应用程序,则您的应用程序很可能始终有机会在下午 5:30 到下午 6 点之间(就在用户使用该应用程序之前)执行后台工作,并且never在一天中的任何其他时间。如果用户非常稀有使用您的应用程序时,在后台工作的机会可能需要几天、几周或几个月。