Is NSTimer expected to fire when app is backgrounded?

前端 未结 2 878
说谎
说谎 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:35

    NSTimer is going to fire whenever the main runloop is running. Apple makes no promises that I know of to unschedule timers or to prevent the main runloop from running. It's your responsibility to unschedule your timers and release resources when you move to the background. Apple isn't going to do it for you. They may, however, kill you for running when you are not supposed to or using too many seconds.

    There are many holes in the system that will allow an app to run when it isn't authorized to. It would be very expensive for the OS to prevent this. But you cannot rely on it.

    0 讨论(0)
  • 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.
    0 讨论(0)
提交回复
热议问题