iOS应用进入后台后计时器和位置更新停止问题的解决办法
由于iOS系统为“伪后台”运行模式,当按下HOME键时,如程序不做任何操作,应用会有5秒的执行缓冲时间,随机程序被挂起,所有任务终端,包括计时器和位置更新等操作,但程序打开后台模式开关后,部分任务可以再后台执行,如音频,定位,蓝牙,下载,VOIP,即便如此,程序的后台运行最多可以延长594秒(大概是10分钟)。不幸的是,程序在声明后台模式后很有可能在app上架时被拒。基于此,我研究出了不用申明后台模式就能让计时器和定位在app进入前台时继续运行的方法。
实现原理如下:
利用iOS的通知机制,在程序进入后台和再次回到前台时发送通知,并记录进入后台的当前时间和再次回到前台的当前时间,算出两者的时间间隔,在程序任何需要的地方添加通知监听者,在监听方法中执行代码块,代码块内参数为通知对象和计算出的时间间隔。以计时器为例,程序再进入后台后,计时器停止运行,此时运用上述方法,在程序再次回到前台时执行代码块中内容,将程序进入后台时计时器的当前时间间隔加上代码块的时间间隔参数就能使计时器准确无误地计时。废话不多说,上代码:
在AppDelegate.m实现文件中:
-(void)applicationDidEnterBackground:(UIApplication*)application{ //Usethismethodtoreleasesharedresources,saveuserdata,invalidatetimers,andstoreenoughapplicationstateinformationtorestoreyourapplicationtoitscurrentstateincaseitisterminatedlater. //Ifyourapplicationsupportsbackgroundexecution,thismethodiscalledinsteadofapplicationWillTerminate:whentheuserquits. [[NSNotificationCenterdefaultCenter]postNotificationName:UIApplicationDidEnterBackgroundNotificationobject:nil]; } -(void)applicationWillEnterForeground:(UIApplication*)application{ //Calledaspartofthetransitionfromthebackgroundtotheactivestate;hereyoucanundomanyofthechangesmadeonenteringthebackground. [[NSNotificationCenterdefaultCenter]postNotificationName:UIApplicationWillEnterForegroundNotificationobject:nil]; }
代码说明:程序进入后台后,利用系统通知机制通知程序进入后台和再次回到前台,监听对象为所有对象。
之后定义一个处理程序进入后台的类YTHandlerEnterBackground
// //YTHandlerEnterBackground.h //分时租赁 // //Createdby柯其谱on17/2/24. //Copyright©2017年柯其谱.Allrightsreserved. // #import#import /**进入后台blocktypedef*/ typedefvoid(^YTHandlerEnterBackgroundBlock)(NSNotification*_Nonnullnote,NSTimeIntervalstayBackgroundTime); /**处理进入后台并计算留在后台时间间隔类*/ @interfaceYTHandlerEnterBackground:NSObject /**添加观察者并处理后台*/ +(void)addObserverUsingBlock:(nullableYTHandlerEnterBackgroundBlock)block; /**移除后台观察者*/ +(void)removeNotificationObserver:(nullableid)observer; @end
在YTHandlerEnterBackground.m实现文件中:
// //YTHandlerEnterBackground.m //分时租赁 // //Createdby柯其谱on17/2/24. //Copyright©2017年柯其谱.Allrightsreserved. // #import"YTHandlerEnterBackground.h" @implementationYTHandlerEnterBackground +(void)addObserverUsingBlock:(YTHandlerEnterBackgroundBlock)block{ __blockCFAbsoluteTimeenterBackgroundTime; [[NSNotificationCenterdefaultCenter]addObserverForName:UIApplicationDidEnterBackgroundNotificationobject:nilqueue:nilusingBlock:^(NSNotification*_Nonnullnote){ if(![note.objectisKindOfClass:[UIApplicationclass]]){ enterBackgroundTime=CFAbsoluteTimeGetCurrent(); } }]; __blockCFAbsoluteTimeenterForegroundTime; [[NSNotificationCenterdefaultCenter]addObserverForName:UIApplicationWillEnterForegroundNotificationobject:nilqueue:nilusingBlock:^(NSNotification*_Nonnullnote){ if(![note.objectisKindOfClass:[UIApplicationclass]]){ enterForegroundTime=CFAbsoluteTimeGetCurrent(); CFAbsoluteTimetimeInterval=enterForegroundTime-enterBackgroundTime; block?block(note,timeInterval):nil; } }]; } +(void)removeNotificationObserver:(id)observer{ if(!observer){ return; } [[NSNotificationCenterdefaultCenter]removeObserver:observername:UIApplicationDidEnterBackgroundNotificationobject:nil]; [[NSNotificationCenterdefaultCenter]removeObserver:observername:UIApplicationWillEnterForegroundNotificationobject:nil]; } @end
该类实现了用来添加通知监听者并处理后台和移除通知监听者的方法,需要注意的是,在addObserverUsingBlock方法中,必须有if(![note.objectisKindOfClass:[UIApplicationclass]])的判断,否则addObserverForName方法中的代码块会执行多次,此代码执行了两次。addObserverUsingBlock方法是在viewWillAppear方法中调用添加通知监听者,在viewWillDisappear方法中调用移除通知监听者。
例如,在使用了计时器NSTimer控制器中:
-(void)viewWillAppear:(BOOL)animated{ [superviewWillAppear:animated]; [YTHandlerEnterBackgroundaddObserverUsingBlock:^(NSNotification*_Nonnullnote,NSTimeIntervalstayBackgroundTime){ self.rentTimerInterval=self.rentTimerInterval-stayBackgroundTime; }]; } -(void)viewWillDisappear:(BOOL)animated{ [superviewWillDisappear:animated]; [self.timerinvalidate]; [YTHandlerEnterBackgroundremoveNotificationObserver:self]; }
我定义了一个倒计时5分钟的计时器对象timer属性,并定义了一个计时器当前倒计时时间间隔rentTimerInterval属性,在添加通知监听者代码块中,rentTimerInterval等于进入后台时的倒计时时间间隔减去程序停留在后台的时间间隔,当计时器再次回到前台时,计时器此时的时间间隔是持续的。虽然计时器并未在后台持续运行,但是使用了此方法,同样实现了计时器的正确即时。
同样的,当程序存在位置更新功能时,当程序进入后台,位置服务对象会自动停止更新,此时的作法依然是调用上述两个处理进入后台的方法,使得程序进入后台后,再次开始定位:
在需要位置更新的类中:
-(void)viewWillAppear:(BOOL)animated{ [superviewWillAppear:animated]; self.locService.delegate=self; [self.locServicestartUserLocationService]; //进入后台再进入前台重新开始定位 [YTHandlerEnterBackgroundaddObserverUsingBlock:^(NSNotification*_Nonnullnote,NSTimeIntervalstayBackgroundTime){ [self.locServicestartUserLocationService]; }]; } -(void)viewWillDisappear:(BOOL)animated{ [superviewWillDisappear:animated]; //停止定位 self.locService.delegate=nil; [self.locServicestopUserLocationService]; //移除后台监听 [YTHandlerEnterBackgroundremoveNotificationObserver:self]; }
此处使用的是百度地图SDK
利用这种方法,像是计时器和位置更新等需要在后台运行的任务都可以实现相应的需求,只是麻烦的是,在任何需要的类中都要调用这两种方法,你可以根据自己的需求,在程序进入后台和再次回到前台时添加别的参数(通知对象参数是必须的),例如保存进入后台前的操作等等。或是定义不同的添加通知监听者的方法以实现不同的需求。
以上所述是小编给大家介绍的iOS应用进入后台后计时器和位置更新停止问题的解决办法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!