iOS解決應用進入後台後計時器和位置更新停止的問題,ios計時器

來源:互聯網
上載者:User

iOS解決應用進入後台後計時器和位置更新停止的問題,ios計時器

  由於iOS系統為“偽後台”運行模式,當按下HOME鍵時,如程式不做任何操作,應用會有5秒的執行緩衝時間,隨機程式被掛起,所有任務終端,包括計時器和位置更新等操作,但程式開啟後台模式開關後,部分任務可以再後台執行,如音頻,定位,藍芽,下載,VOIP,即便如此,程式的後台運行最多可以延長594秒(大概是10分鐘)。不幸的是,程式在聲明後台模式後很有可能在app上架時被拒。基於此,我研究出了不用申明後台模式就能讓計時器和定位在app進入前台時繼續啟動並執行方法。

  實現原理如下:

  利用iOS的通知機制,在程式進入後台和再次回到前台時發送通知,並記錄進入背景目前時間和再次回到前台的目前時間,算出兩者的時間間隔,在程式任何需要的地方添加通知監聽者,在監聽方法中執行代碼塊,代碼塊內參數為通知對象和計算出的時間間隔。以計時器為例,程式再進入後台後,計時器停止運行,此時運用上述方法,在程式再次回到前台時執行代碼塊中內容,將程式進入後台時計時器的目前時間間隔加上代碼塊的時間間隔參數就能使計時器準確無誤地計時。廢話不多說,上代碼:

在AppDelegate.m實現檔案中:

- (void)applicationDidEnterBackground:(UIApplication *)application {    // 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.    [[NSNotificationCenter defaultCenter]postNotificationName:UIApplicationDidEnterBackgroundNotification object:nil];}- (void)applicationWillEnterForeground:(UIApplication *)application {    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.    [[NSNotificationCenter defaultCenter]postNotificationName:UIApplicationWillEnterForegroundNotification object:nil];}

代碼說明:程式進入後台後,利用系統通知機制通知程式進入後台和再次回到前台,監聽對象為所有對象。

之後定義一個處理常式進入背景類YTHandlerEnterBackground

////  YTHandlerEnterBackground.h//  分時租賃////  Created by 柯其譜 on 17/2/24.//  Copyright  2017年 柯其譜. All rights reserved.//#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>/** 進入後台block typedef */typedef void(^YTHandlerEnterBackgroundBlock)(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime);/** 處理進入後台並計算留在後台時間間隔類 */@interface YTHandlerEnterBackground : NSObject/** 添加觀察者並處理後台 */+ (void)addObserverUsingBlock:(nullable YTHandlerEnterBackgroundBlock)block;/** 移除後台觀察者 */+ (void)removeNotificationObserver:(nullable id)observer;@end

在YTHandlerEnterBackground.m實現檔案中:

 

////  YTHandlerEnterBackground.m//  分時租賃////  Created by 柯其譜 on 17/2/24.//  Copyright  2017年 柯其譜. All rights reserved.//#import "YTHandlerEnterBackground.h"@implementation YTHandlerEnterBackground+ (void)addObserverUsingBlock:(YTHandlerEnterBackgroundBlock)block {    __block CFAbsoluteTime enterBackgroundTime;    [[NSNotificationCenter defaultCenter]addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {        if (![note.object isKindOfClass:[UIApplication class]]) {            enterBackgroundTime = CFAbsoluteTimeGetCurrent();        }    }];    __block CFAbsoluteTime enterForegroundTime;    [[NSNotificationCenter defaultCenter]addObserverForName:UIApplicationWillEnterForegroundNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {        if (![note.object isKindOfClass:[UIApplication class]]) {            enterForegroundTime = CFAbsoluteTimeGetCurrent();            CFAbsoluteTime timeInterval = enterForegroundTime-enterBackgroundTime;            block? block(note, timeInterval): nil;        }    }];}+ (void)removeNotificationObserver:(id)observer {    if (!observer) {        return;    }    [[NSNotificationCenter defaultCenter]removeObserver:observer name:UIApplicationDidEnterBackgroundNotification object:nil];    [[NSNotificationCenter defaultCenter]removeObserver:observer name:UIApplicationWillEnterForegroundNotification object:nil];}@end

 

該類實現了用來添加通知監聽者並處理後台和移除通知監聽者的方法,需要注意的是,在addObserverUsingBlock方法中,必須有if (![note.object isKindOfClass:[UIApplication class]])的判斷,否則addObserverForName方法中的代碼塊會執行多次,此代碼執行了兩次。addObserverUsingBlock方法是在viewWillAppear方法中調用添加通知監聽者,在viewWillDisappear方法中調用移除通知監聽者。

 

例如,在使用了計時器NSTimer控制器中:

- (void)viewWillAppear:(BOOL)animated {    [super viewWillAppear:animated];    [YTHandlerEnterBackground addObserverUsingBlock:^(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime) {        self.rentTimerInterval = self.rentTimerInterval-stayBackgroundTime;    }];}- (void)viewWillDisappear:(BOOL)animated {    [super viewWillDisappear:animated];    [self.timer invalidate];    [YTHandlerEnterBackground removeNotificationObserver:self];}

我定義了一個倒計時5分鐘的計時器對象timer屬性,並定義了一個計時器當前倒計時時間間隔rentTimerInterval屬性,在添加通知監聽者代碼塊中,rentTimerInterval等於進入後台時的倒計時時間間隔減去程式停留在背景時間間隔,當計時器再次回到前台時,計時器此時的時間間隔是持續的。雖然計時器並未在後台持續運行,但是使用了此方法,同樣實現了計時器的正確即時。

 

同樣的,當程式存在位置更新功能時,當程式進入後台,位置服務物件會自動停止更新,此時的作法依然是調用上述兩個處理進入背景方法,使得程式進入後台後,再次開始定位:

在需要位置更新的類中:

 

- (void)viewWillAppear:(BOOL)animated {    [super viewWillAppear:animated];    self.locService.delegate = self;    [self.locService startUserLocationService];    //進入後台再進入前台重新開始定位    [YTHandlerEnterBackground addObserverUsingBlock:^(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime) {        [self.locService startUserLocationService];    }];}- (void)viewWillDisappear:(BOOL)animated {    [super viewWillDisappear:animated];    //停止定位    self.locService.delegate = nil;    [self.locService stopUserLocationService];    //移除後台監聽    [YTHandlerEnterBackground removeNotificationObserver:self];}

此處使用的是百度地圖SDK

 

利用這種方法,像是計時器和位置更新等需要在後台啟動並執行任務都可以實現相應的需求,只是麻煩的是,在任何需要的類中都要調用這兩種方法,你可以根據自己的需求,在程式進入後台和再次回到前台時添加別的參數(通知對象參數是必須的),例如儲存進入後台前的操作等等。或是定義不同的添加通知監聽者的方法以實現不同的需求。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.