在程序被送入后台時,向 iOS 借點時間,來完成一個長期任務


   

12.2.2. 方案 

使用UIApplicationbeginBackgroundTaskWithExpirationHandler: 實例方法。在你完成任務后,調用UIApplicationendBackgroundTask:方法。 

12.2.3. 討論 

當一個iOS應用被送到后台,它的主線程會被暫停。你用NSThreaddetachNewThreadSelector:toTar get:withObject:類方法創建的線程也被掛起了。如果你想在后台完成一個長期任務,就必須調用UIApplicationbeginBackgroundTaskWithExpirationHandler:實例方法,來向iOS借點時間。UIApplicationbackgroundTimeRemaining屬性包含了程序完成他的任務可以使用的秒數。如果在這個期限內,長期任務沒有被完成,iOS將終止程序。每個對beginBackgroundTaskWithExpirationHandler:方法的調用,必須要相應的調用endBackgroundTask:方法(UIApplication的另一個實例方法)。也就是說,如果你向iOS要更多時間來完成一個任務,你必須告訴iOS你什么時候能完成那個任務,那時,你的程序將iOS 5 Programming Cookbook www.devdiv.com 翻譯整理 

DevDiv 翻譯:kyelup cloudhsu 耐心摩卡 wangli2003j3 xiebaochun dymx101 jimmylianf BeyondVincent 20 DevDiv 校對:laigb kyelup DevDiv 編輯:BeyondVincent 版本 1.0 | 2012 07 30 日 

 

和其所有被暫停的線程被放入后台。 

當你的程序在前台時,UIApplicationbackgroundTimeRemaining屬性等於DBL_MAX常量,這是double類型可表示的最大值(和這個值相當的integer通常等於-1)。在iOS被要求在程序被完全掛起之前給於更多的執行時間,這個屬性指明了在完成任務前程序擁有多少秒。 

在程序中你可以多次調用beginBackgroundTaskWithExpirationHandler:方法。要記住的重點是,當iOS為你的程序返回一個token或者任務標識(task identifier)時,你都必須調用endBackgroundTask:方法,在運行的任務結束時,用來標志任務結束。如果你不這么做的話,iOS會終止你的程序。 

在后台時,程序不應該執行完全的功能,也不應該處理大量數據。事實上,他們只應該完成一個長期任務。 

比如,一個程序正在調用一個web service API,並且還沒有從服務器上的那個API接收到響應。在此期間,如果程序被送入后台,它可以請求更多的時間,直到它從服務器收到響應。一旦響應被接收,程序必須保存其狀態,並調用UIApplicationendBackgroundTask:實例方法將任務標記為完成。 

讓我們看一個例子。我將從在應用程序委托中定義一個UIBackgroundTaskIdentifier類型的屬性開始。同時,讓我們定義一個NSTimer,當程序被送到后台時,我們將用它每隔1秒向控制台窗口輸出一條消息: 

#import <UIKit/UIKit.h> 

@interface Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate : UIResponder <UIApplicationDelegate> 

@property (nonatomic, strong) UIWindow *window; 

@property (nonatomic, unsafe_unretained) UIBackgroundTaskIdentifier backgroundTaskIdentifier; 

@property (nonatomic, strong) NSTimer *myTimer; 

@end 

接下來我們繼續同步屬性: 

#import "Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate.h" @implementation Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate 

@synthesize window = _window; 

@synthesize backgroundTaskIdentifier; @synthesize myTimer; 

現在,讓我們創建定時器,並在程序被送到后台時啟動它: 

- (BOOL) isMultitaskingSupported{ 

BOOL result = NO; 

if ([[UIDevice currentDevice] 

respondsToSelector:@selector(isMultitaskingSupported)]){ result = [[UIDevice currentDevice] isMultitaskingSupported]; 

return result; 

- (void) timerMethod:(NSTimer *)paramSender{ 

NSTimeInterval backgroundTimeRemaining = 

[[UIApplication sharedApplication] backgroundTimeRemaining]; 

if (backgroundTimeRemaining == DBL_MAX){ NSLog(@"Background Time Remaining = Undetermined"); 

} else { iOS 5 Programming Cookbook www.devdiv.com 翻譯整理 

DevDiv 翻譯:kyelup cloudhsu 耐心摩卡 wangli2003j3 xiebaochun dymx101 jimmylianf BeyondVincent 21 DevDiv 校對:laigb kyelup DevDiv 編輯:BeyondVincent 版本 1.0 | 2012 07 30 日 

 

NSLog(@"Background Time Remaining = %.02f Seconds", 

backgroundTimeRemaining); 

} } 

- (void)applicationDidEnterBackground:(UIApplication *)application{ 

if ([self isMultitaskingSupported] == NO){ 

return; } 

self.myTimer = 

[NSTimer scheduledTimerWithTimeInterval:1.0f 

target:self 

selector:@selector(timerMethod:) userInfo:nil 

repeats:YES]; 

self.backgroundTaskIdentifier = 

[application beginBackgroundTaskWithExpirationHandler:^(void) { [self endBackgroundTask]; 

}]; } 

你可以看到,在后台任務的完成處理者(completion handler)中,我們調用了應用程序委托的endBackgroundTask方法。這是一個我們編寫的方法,如下: 

- (void) endBackgroundTask{ 

dispatch_queue_t mainQueue = dispatch_get_main_queue(); 

__weak Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate *weakSelf = self; 

dispatch_async(mainQueue, ^(void) { 

Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate *strongSelf = weakSelf; 

if (strongSelf != nil){ 

[strongSelf.myTimer invalidate]; 

[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier]; 

strongSelf.backgroundTaskIdentifier = UIBackgroundTaskInvalid; } 

}); } 

在長期任務結束后,我們需要做一些事情進行清理: 

1. 結束所有的線程和定時器,不管他們是基礎定時器還是GCD中創建的。 

2.調用UIApplicationendBackgroundTask:方法來結束后台任務。 

3.將任務標識設置為UIBackgroundTaskInvalid,標志我們的任務結束。 

最后,當我們的應用回到前台,如果我們的后台任務還在執行中,我們需要確保我們在干掉它: 

- (void)applicationWillEnterForeground:(UIApplication *)application{ 

if (self.backgroundTaskIdentifier != UIBackgroundTaskInvalid){ 

[self endBackgroundTask]; } 

在我們的例子中,不論何時程序被送到后台,我們都會要求更多時間以完成一個長期任務(例如,在這里是我們計時器的代碼)。在我們的時間里,我們不斷的讀取UIApplication實例中backgroundTimeRemaining屬性的值,將它打印到控制台。在UIApplicationbeginBackgroundTask WithExpirationHandler: 實例方法中,在程序的額外時間內完成一個長期任務之前,我們提供的代碼將被執行(一版大概在任務過期前510秒)。在此,我們只要調用UIApplicationendBackgroundTask:實例方法來結束任務。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM