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

來源:互聯網
上載者:User
   

12.2.2. 方案 

使用UIApplication的beginBackgroundTaskWithExpirationHandler: 執行個體方法。在你完成任務後,調用UIApplication的endBackgroundTask:方法。 

12.2.3. 討論 

當一個iOS應用被送到後台,它的主線程會被暫停。你用NSThread的detachNewThreadSelector:toTar get:withObject:類方法建立的線程也被掛起了。如果你想在後台完成一個長期任務,就必須調用UIApplication的beginBackgroundTaskWithExpirationHandler:執行個體方法,來向iOS借點時間。UIApplication的backgroundTimeRemaining屬性包含了程式完成他的任務可以使用的秒數。如果在這個期限內,長期任務沒有被完成,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 日 

 

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

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

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

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

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

讓我們看一個例子。我將從在應用程式委託中定義一個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.調用UIApplication的endBackgroundTask:方法來結束背景工作。 

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

最後,當我們的應用回到前台,如果我們的背景工作還在執行中,我們需要確保我們在幹掉它: 

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

if (self.backgroundTaskIdentifier != UIBackgroundTaskInvalid){ 

[self endBackgroundTask]; } 

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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.