17

まったくわかりませんがNSTimer、私のアプリでは間違いなくバックグラウンドで実行されています。タイマーによって実行されるNSLogin メソッドがあり、バックグラウンドでログを記録しています。iOS 4.2.1 を搭載した iPhone 4 です。Info.plist でロケーション バックグラウンド サポートを宣言しました。

ここや他の場所でドキュメントと多くの議論を読みましたが、それは不可能です。iOSのバグですか?または文書化されていない機能ですか?私はそれを使用したくなく、近い将来、たとえば iOS 4.3 の登場により、Apple が黙ってそれを「修正」し、アプリが機能しなくなることを知りたくありません。

誰かそれについてもっと知っていますか?

4

2 に答える 2

33

NSTimerメインのrunloopが実行されているときはいつでも起動します。Appleは、タイマーのスケジュールを解除したり、メインのrunloopが実行されないようにしたりすることを私が知っていることを約束しません。バックグラウンドに移動したときにタイマーのスケジュールを解除し、リソースを解放するのはあなたの責任です。Appleはあなたのためにそれをするつもりはありません。ただし、想定外の場合や秒数が多すぎる場合は、実行のために殺される可能性があります。

システムには、許可されていないときにアプリを実行できるようにする多くの穴があります。OSがこれを防ぐのは非常に費用がかかります。しかし、あなたはそれに頼ることはできません。

于 2011-03-03T23:16:52.963 に答える
8

バックグラウンド実行モードでタイマーを起動できます。いくつかのトリックがあります:

  • でバックグラウンド実行を選択する必要があります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 アプリがロックされた後、タイマーは起動しません。
于 2013-07-03T10:32:07.243 に答える