iPhone 4 is there an absolutely certain way to have a long term NSTimer fire

后端 未结 3 855
予麋鹿
予麋鹿 2021-01-15 05:52

I keep having troubles with my NSTimers and background selectors. It is driving me nuts and takes a very long time to try out each tweak. To preserve my sanity, and the sani

相关标签:
3条回答
  • 2021-01-15 05:58

    One of the myriad issues with NSTimers is their run-loop dependency. Every thread has a single run loop. If you schedule a timer on a background thread, it will be scheduled on that thread's run loop. If that thread is short lived, which background threads often are, that timer will quietly die with it.

    The solution is to guarantee the timer is run on a thread that will be alive when the timer fires. The best way to do these dedicated background timers in my experience is to not use NSTimer at all, and go for GCD timers instead. Better men than I have coded up GCD powered timers. I personally prefer Mike Ash's article and implementation, which comes with an explanation.

    0 讨论(0)
  • 2021-01-15 06:01

    For as long as you depend on using scheduledTimerWithTimeInterval:... you cannot achieve what you want:
    The timer will always be tied to the run-loop of the calling thread.

    If there is no run-loop associated with that thread by the time of that message's invocation, there surely is one when the method returns as -[NSRunLoop currentRunLoop] creates a run-loop if necessary.

    What you can do, if you don't like the other APIs for creation of a timer, is providing a category on NSTimer, which takes care of all the scheduling and so forth and that you can reuse in other projects.

    Here is an example of what such a category might look like:

    #pragma mark - setting up a timer:
    + (NSTimer *)yourPrefix_mainLoopScheduledTimerWithTimeInterval:(NSTimeInterval)interval target:(id)target selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
    {
        NSTimer *timer = [self yourPrefix_timerWithTimeInterval:interval target:target selector:selector userInfo:userInfo repeats:shouldRepeat];
    
        void (^scheduler)() = ^{
            [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        };
    
        if ([NSThread isMainThread]) {
            scheduler();
        } else {
            // you should really be able to rely on the fact, that the timer is ready to roll, when this method returns
            dispatch_sync(dispatch_get_main_queue(), scheduler);
        }
    
        return timer;
    }
    
    // this is just a convenience for the times where you actually want an _unscheduled_ timer
    + (NSTimer *)yourPrefix_timerWithTimeInterval:(NSTimeInterval)interval target:(id)target selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
    {
        NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:interval];
    
        NSTimer *timer = [[self alloc] initWithFireDate:fireDate interval:interval target:target selector:selector userInfo:userInfo repeats:shouldRepeat];
    
        return [timer autorelease];
    }
    
    #pragma mark - tearing it down:
    - (void)yourPrefix_invalidateMainLoopTimer
    {
        [self yourPrefix_invalidateMainLoopTimerAsynchronous:NO];
    }
    
    - (void)yourPrefix_invalidateMainLoopTimerAsynchronous:(BOOL)returnsImmediately
    {
        void (^invalidator)() = ^{
            [self invalidate];
        };
    
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
        if (returnsImmediately) {
            dispatch_async(mainQueue, invalidator);
            return;
        }
    
        if (![NSThread isMainThread]) {
            dispatch_sync(mainQueue, invalidator);
            return;
        }
    
        invalidator();
    }
    

    Note the thread checks before using dispatch_sync because...

    dispatch_sync

    Discussion

    […] Calling this function and targeting the current queue results in deadlock.

    (from The GCD Reference — emphasis mine)

    0 讨论(0)
  • 2021-01-15 06:09

    Use local notification instead.

    0 讨论(0)
提交回复
热议问题