[英]For iOS, what is the difference of the Concurrency Programming Guide and the Threading Programming Guide?
[英]Apple programming guide for iOS background execution guide example?
所以在這個頁面上有一個關於后台執行的例子: https : //developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072- CH4-SW1 ,這是一個例子:
- (void)applicationDidEnterBackground:(UIApplication *)application {
bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task, preferably in chunks.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
據說bgTask
在類中被定義為變量。 因此,每個類(對象)實例都有一個bgTask
屬性。 如果在異步塊完成之前多次調用applicationDidEnterBackground
,那么競爭條件是否存在危險? 我的意思是bgTask
會改變它的值,而endBackgroundTask
會被調用新的任務值,而不是舊的值?
這不是一個更好的解決方案:
__block UIBackgroundTaskIdentifier bgTask;
在調用beginBackgroundTaskWithName
之前?
每個對象都有一個bgTask
實例,但這是在AppDelegate
,而不是一般的VC或對象。 因此,從技術上講,只有一個bgTask
實例在工作。
但這仍然會產生問題。 因為如果這個方法被調用兩次,它將覆蓋bgTask
的值。 我的第一個想法是,在退出應用程序時,不止一次,以前的所有任務都將過期。 但經過測試意識到情況並非如此(這是IMO的一件好事)。 發生的事情是bgTask
被覆蓋(如預期的那樣)並且新值被傳遞給第一個endBackgroundTask:
call。 之后立即將bgTask
設置為UIBackgroundTaskInvalid
,將其清除,並將清除的值傳遞給對endBackgroundTask:
任何后續調用endBackgroundTask:
。 這顯然導致了一個不干凈的終止,因為並非所有唯一的id都已經結束,導致expiration
處理程序在任何剩余的后台任務上執行。
話雖如此,我相信你對使用局部變量的假設是正確的。 如果你試試這段代碼(放在AppDelegate
applicationDidEnterBackground:
中AppDelegate
:
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
NSLog(@"Expired");
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
NSLog(@"Backgrounded: %@", @(bgTask));
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task, preferably in chunks.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"Done! %@", @(bgTask));
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
});
您將看到每個本地bgTask
被分配了一個唯一值,並在10秒后正確完成(根據dispatch_after
調用)。
我認為你要解決的問題如下:
應用程序被發送到Background
狀態,iOS調用applicationDidEnterBackground:
.
后台任務已啟動,可能需要幾分鍾時間。
在此期間,應用程序再次被激活,並再次發送到后台,再次調用applicationDidEnterBackground:
,並啟動另一個后台任務,如果它不是塊變量,則變量bgTask
將被覆蓋。 這是對的。 因此, bgTask
確實應該是一個塊變量。
與此問題相關的問題是,如果已啟動多個后台任務,您將如何完成后台執行。 這里給出了一個例子,你如何做到這一點 。
我們的想法是擁有一個計算活動后台任務的變量。 一旦完成所有這些,就可以終止后台執行。
你是對的,當第二次調用時, applicationDidEnterBackground
會引起問題。 但是為了第二次調用該方法,首先需要將應用程序放入前台。 所以解決方案很簡單。 只需從applicationWillEnterForeground
調用您的到期處理applicationWillEnterForeground
:
- (void)expireBackgroundTask {
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
[self expireBackgroundTask];
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task, preferably in chunks.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[self expireBackgroundTask];
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.