2015-11-07 51 views
3

我的一些用戶正在發生這種崩潰(據他們說,使用應用程序4-5分鐘後會發生這種情況),但我無法自行重現:iOS應用程序「有超出允許時間的主動斷言 - 偶爾發生崩潰」

Application Specific Information: 
<BKNewProcess: 0x175466c0; com.zsquare.iPadApp; pid: 5005; hostpid: -1> has active assertions beyond permitted time: 
{(
    <BKProcessAssertion: 0x17545c90> id: 48-3A424578-FF1D-4484-9026-B4C6A83AD7EF name: Background Content Fetching (191) process: <BKNewProcess: 0x175466c0; .com.zsquare.ijournalPad; pid: 5005; hostpid: -1> permittedBackgroundDuration: 30.000000 reason: backgroundContentFetching owner pid:48 preventSuspend preventThrottleDownUI preventIdleSleep preventSuspendOnSleep 
)} 

Elapsed total CPU time (seconds): 0.460 (user 0.460, system 0.000), 2% CPU 
Elapsed application CPU time (seconds): 0.013, 0% CPU 

Filtered syslog: None found 

Thread 0 name: Dispatch queue: com.apple.main-thread 
Thread 0: 
0 libsystem_kernel.dylib   0x362a4ff0 mach_msg_trap + 20 
1 libsystem_kernel.dylib   0x362a4df4 mach_msg + 38 
2 CoreFoundation     0x23fa58c4 __CFRunLoopServiceMachPort + 134 
3 CoreFoundation     0x23fa3c4c __CFRunLoopRun + 1034 
4 CoreFoundation     0x23ef7118 CFRunLoopRunSpecific + 518 
5 CoreFoundation     0x23ef6f04 CFRunLoopRunInMode + 106 
6 GraphicsServices    0x2d081ac8 GSEventRunModal + 158 
7 UIKit       0x28139f14 UIApplicationMain + 142 
8 SimpleList-iPad     0x0000f116 main (main.m:17) 
9 libdyld.dylib     0x361e9872 start + 0 

現在我已經看了,與此崩潰對付其它各種做題,但沒有一個答案已經出現了對我很有幫助,所以我想我會在這裏發表我自己的設置和代碼。

首先,發生這種情況的功能與應該在應用程序中運行的重複任務有關。對於這一點,我有一個計時器在應用程序重複第一次啓動應用程序時:

- (void) setupRepeatTimer { 

self.repeatTimer = [NSTimer scheduledTimerWithTimeInterval: 60.0 target:self selector:@selector(checkForAutomaticTaskTime:) userInfo:nil repeats: YES]; 
self.repeatTimer.tolerance = 1.0; 

}

- (void) checkForAutomaticTaskTime: (NSTimer *) timer { 

    if (self.taskIdentifier) { 
    [[UIApplication sharedApplication] endBackgroundTask: self.taskIdentifier]; 
    } 

    self.taskIdentifier = UIBackgroundTaskInvalid; 
    [self beginBackgroundUpdateTask]; 


    // simplified, but there are more conditional checks here 
    if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive && setting_enabled_for_automatic_task) { 
     [self startAutomaticBackup]; 
    } else { 
     [self endBackgroundUpdateTask]; 
    } 
} 

需要運行是可變大小,取決於用戶的數據備份。下面是這個普通代碼:

- (void) startAutomaticBackup { 

    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     [self runBackupWithCompletionBlock:^(NSString * filename) { 

      dispatch_async(dispatch_get_main_queue(), ^{ 
       // finish on the main thread 
       [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 

       [self endBackgroundUpdateTask]; 

      }); 
     }]; 
    }); 
} 

只是可以肯定的是,beginBackgroundUpdateTaskendBackgroundUpdateTask看起來就像那些從代碼樣本中SO和蘋果指南:

- (void) beginBackgroundUpdateTask 
{ 
    self.taskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"CJAutoBackup" expirationHandler:^{ 
     NSLog(@"beginBackgroundTask about to end = %lu", (unsigned long)self.taskIdentifier); 
     [self endBackgroundUpdateTask]; 
    }]; 
} 

- (void) endBackgroundUpdateTask 
{ 
    if (self.taskIdentifier) { 
     [[UIApplication sharedApplication] endBackgroundTask: self.taskIdentifier]; 
     self.taskIdentifier = UIBackgroundTaskInvalid; 
    } 
} 

====

這就是我的設置。從用戶描述看,應用程序運行了4-5分鐘後,該應用程序在前臺出現崩潰報告時崩潰。如果他們禁用自動備份設置,則應用程序會再次正常工作。

這裏的主要困惑是應用程序崩潰時,應用程序在前臺使用它,而不是背景,但錯誤消息談論後臺任務斷言。這怎麼可能?

另外,我能做些什麼來防止這個問題呢?我見過UIApplication的backgroundTimeRemaining屬性,但我不確定在我的示例中如何或在哪裏使用它。

使用NSTimer是否會導致任何併發症?在設備上,如果應用程序已經在後臺,它似乎不會觸發計時器。

欣賞幫助。

回答

3

這是一個線程問題。如你所懷疑的那樣,問題確實是你的開始/結束後臺任務調用的保理和架構。您正在嘗試將一個後臺任務標識符保留爲屬性,然後無論實際任務需要多長時間(在後臺線程上),您都會每60秒重複更改一次。這種令人困惑的僞循環體系結構導致您的後臺任務與其標識符不同步,因此後臺任務的時間將會過期,而無需使用適當的標識符調用endBackgroundTask

您需要修改此架構,以便您有一個後臺任務標識符每個任務,因此保持一切分開。我想你會發現最簡單的方法是將每個自動備份表示爲一個單獨的NSOperation。

+0

謝謝。計時器應該在任何現有的標識符上調用'endBackgroundTask',並在計時器開始時將其標記爲無效,然後開始另一個任務,那麼這仍然是一個問題?再看一遍,它看起來問題可能是'備份'過程可能需要60秒以上,所以當它完成並調用完成塊時,它會在過期的標識符上調用'endBackgroundTask'?會產生相同的問題和堆棧跟蹤,還是你認爲它仍然有一些標識符沒有得到'endBackgroundTask'的問題? –

+0

我想我們說的是同樣的事情。看,我無法弄清楚你的代碼是幹什麼的,我也不認爲你可以。但是我們確實知道您只有一個標識符,但您可以同時執行多個備份任務。這是瘋狂的,即使_never_發生了(聽起來像在你的測試中沒有)。因此我的建議是:每個備份都是自己的NSOperation,它有自己的後臺任務和自己的後臺任務標識符。沒有更多的「循環」!你的代碼會更簡單。 – matt

+0

我同意一般觀點,我認爲我看到了問題。解決辦法是從NSTimer函數中取出taskIdentifier,並且只調用它來環繞實際的備份功能(同時添加一個布爾值以防止在備份運行時調用備份代碼)。那樣,一次只有一個背景任務正在進行。 –

相關問題