我有位置服务的背景模式,并且每30分钟发送一次服务器的位置(纬度和经度).现在我在控制台上打印相同.似乎工作了一段时间,但我想知道如何在这种情况下使用NSTimer.我应该从哪里打电话呢?
import UIKit import CoreLocation @UIApplicationMain class AppDelegate: UIResponder,UIApplicationDelegate,CLLocationManagerDelegate { var window: UIWindow? var locationManager = CLLocationManager() func application(application: UIApplication,didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // Override point for customization after application launch. return true } func applicationWillResignActive(application: UIApplication) { // 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. } func applicationDidEnterBackground(application: UIApplication) { // Use this method to release shared resources,save user data,invalidate timers,and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution,this method is called instead of applicationWillTerminate: when the user quits. self.locationManager.delegate = self self.locationManager.startUpdatingLocation() // I know i should be using signification location option here. this is just for testing now. } func locationManager(manager: CLLocationManager!,didUpdateToLocation newLocation: CLLocation!,fromLocation oldLocation: CLLocation!) { self.sendBackgroundLocationToServer(newLocation); } func sendBackgroundLocationToServer(location: CLLocation) { var bgTask = UIBackgroundTaskIdentifier() bgTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler { () -> Void in UIApplication.sharedApplication().endBackgroundTask(bgTask) } println(location.coordinate.latitude) if (bgTask != UIBackgroundTaskInvalid) { UIApplication.sharedApplication().endBackgroundTask(bgTask); bgTask = UIBackgroundTaskInvalid; } } func applicationWillEnterForeground(application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. application.beginBackgroundTaskWithExpirationHandler{} } func applicationDidBecomeActive(application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was prevIoUsly in the background,optionally refresh the user interface. application.beginBackgroundTaskWithExpirationHandler{} } func applicationWillTerminate(application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. application.beginBackgroundTaskWithExpirationHandler{} } }
可能调用application.beginBackgroundTaskWithExpirationHandler {}是一个坏主意?这里有什么选择?
解决方法
beginBackgroundTask …的想法是启动一个有限长度的任务,以便如果用户离开应用程序,它将在后台任务中持续运行一段短暂的有限时间段(相信是3分钟).在时间用完之前,您必须调用endBackgroundTask,否则应用程序将被终止.
所以,遗憾的是,后台任务机制并不适合你所期望的意图.然而,还有一组窄的特殊背景模式,用于在一组功能(VOIP,音频等)之外继续进行背景操作.有关更多信息,请参阅App Programming Guide for iOS: Background Execution的“实施长时间运行任务”部分.
现在,这些背景模式之一是用于“位置”服务.所以,如果这是您的应用程序的核心功能,对于正常的功能至关重要,那么您可以注册位置背景模式,并且您的应用程序将继续在后台运行.从那里可以按照您的意图使用NSTimer.但是,如果这种背景位置模式不是应用程序的基本功能,那么Apple可能会拒绝您的应用程序来请求不需要的后台模式.
如果您实际启用了真正的后台操作,则可以:
NSTimer.scheduledTimerWithTimeInterval(60 * 30,target: self,selector: Selector("handleTimer:"),userInfo: nil,repeats: true)
你的计时器处理器看起来像:
func handleTimer(timer: NSTimer) { // start location services,here // Remember,have `didUpdateLocations` stop location services // when good location received }
顺便问一下,您应该注意,每30分钟启动标准的位置服务可能会耗尽设备电池.您可以考虑使用电池高效的“重大变更”定位服务.这也有助于每次用户移动一些显着距离时自动唤醒您的应用程序(例如,以km为单位测量;我相信它是通过移动到不同的信元塔来触发的).这种方法还具有这样的优点,它可以消除使用定时器并保持应用在后台运行的需要.