Is NSTimer expected to fire when app is backgrounded?

前端 未结 2 877
说谎
说谎 2020-11-27 18:57

I don\'t understand it at all but NSTimer in my app definitely is running in background. I have a NSLog in method run by the timer and it is loggin

2条回答
  •  有刺的猬
    2020-11-27 19:43

    You can have a timer fire while in background execution mode. There are a couple of tricks:

    • You need to opt into background execution with beginBackgroundTaskWithExpirationHandler.
    • If you create the NSTimer on a background thread, you need to add it to the mainRunLoop manually.

    - (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");
    }
    

    Notes

    • Apps only get ~ 10 mins of background execution - after this the timer will stop firing.
    • As of iOS 7 when the device is locked it will suspend the foreground app almost instantly. The timer will not fire after an iOS 7 app is locked.

提交回复
热议问题