2011-03-03 162 views
16

我完全不理解它,但在我的應用程序中NSTimer肯定是在後臺運行。我有一個NSLog mehod由計時器運行,它在後臺進行日誌記錄。它在iOS 4.2.1的iPhone 4上。我已經在Info.plist中聲明瞭位置背景支持。NSTimer在後臺工作

我在這裏和其他地方閱讀了文檔和許多討論,它應該是不可能的。它是一個iOS錯誤?還是無證的功能?我不想使用它並在不久的將來發現,例如隨着iOS 4.3的到來,Apple默默「修復」它,該應用程序將無法工作。

有人知道更多關於它嗎?

回答

31

NSTimer將在主循環運行時觸發。蘋果公司對我所知道的計劃外定時器或防止主要runloop運行沒有任何承諾。當您移動到後臺時,您有責任取消您的計時器並釋放資源。蘋果不會爲你做。但是,他們可能會在你不應該使用或使用太多秒的時候殺死你。

系統中有許多漏洞會允許應用程序在未授權時運行。操作系統要防止這種情況會非常昂貴。但你不能依靠它。

+0

好吧,這對我來說是足夠的答案。謝謝。我不知道我是否錯過了一些東西。我絕對不會使用它。 – JakubM 2011-03-04 09:29:41

8

can在後臺執行模式下有一個定時器火警。有幾個技巧:

  • 你需要選擇與beginBackgroundTaskWithExpirationHandler後臺執行。
  • 如果您在後臺線程上創建NSTimer,則需要手動將其添加到mainRunLoop。

- (void)viewDidLoad 
{ 
    // Avoid a retain cycle 
    __weak ViewController * weakSelf = self; 

    // Declare the start of a background task 
    // If you do not do this then the mainRunLoop will stop 
    // firing when the application enters the background 
    self.backgroundTaskIdentifier = 
    [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 

     [[UIApplication sharedApplication] endBackgroundTask:self.backgroundIdentifier]; 
    }]; 

    // Make sure you end the background task when you no longer need background execution: 
    // [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier]; 


    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     // Since we are not on the main run loop this will NOT work: 
     [NSTimer scheduledTimerWithTimeInterval:0.5 
             target:self 
             selector:@selector(timerDidFire:) 
             userInfo:nil 
             repeats:YES]; 

     // This is because the |scheduledTimerWithTimeInterval| uses 
     // [NSRunLoop currentRunLoop] which will return a new background run loop 
     // which will not be currently running. 
     // Instead do this: 
     NSTimer * timer = 
     [NSTimer timerWithTimeInterval:0.5 
           target:weakSelf 
           selector:@selector(timerDidFire:) 
           userInfo:nil 
           repeats:YES]; 

     [[NSRunLoop mainRunLoop] addTimer:timer 
            forMode:NSDefaultRunLoopMode]; 
     // or use |NSRunLoopCommonModes| if you want the timer to fire while scrolling 
    }); 
} 

- (void) timerDidFire:(NSTimer *)timer 
{ 
    // This method might be called when the application is in the background. 
    // Ensure you do not do anything that will trigger the GPU (e.g. animations) 
    // See: http://developer.apple.com/library/ios/DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW47 
    NSLog(@"Timer did fire"); 
} 

注意

  • 應用程序只能拿到〜後臺執行的10分鐘 - 在此之後,計時器會停止射擊。
  • 截至iOS 7當設備是鎖定它會暫停幾乎立即前景應用程序。計時器在iOS 7應用程序被鎖定後不會觸發。
+0

偉大的和平代碼,這將幫助我完成我的應用程序,THNX :)。一個小問題,你在「當應用程序處於後臺時可能調用此方法」時會怎麼想?我想在3小時內使用它來從服務器更新數據。有更好的方法嗎? – MQoder 2013-12-20 13:18:33

+1

將您的應用程序放入後臺時最多隻能運行10分鐘。從iOS 7開始,這10分鐘可以不相交。您可能可以使用iOS7的新背景模式:後臺傳輸用於大量上傳/下載或無聲推動以遠程喚醒您的應用程序。 – Robert 2013-12-20 14:26:07

+1

此代碼示例表明應用程序本身的前景/背景狀態與主隊列與全局隊列問題之間存在混淆。不需要將定時器的調度分派給全局隊列。只需在主隊列上安排計時器,就像正常一樣,'beginBackgroundTaskWithExpirationHandler'將使應用程序保持活動幾分鐘。 – Rob 2015-01-12 04:26:13