The selector of my NSTimer does not run. Why?

2020-03-26 05:51发布

问题:

My code is:

-(void) timerRun{...}

-(void) createTimer
{
   NSTimer *timer;
   timer = [NSTimer timerWithTimeInterval:1.0 
                                   target:self 
                                 selector:@selector(timerRun) 
                                 userInfo:nil 
                                  repeats:YES];
}

viewDidLoad
{
   [NSThread detachNewThreadSelector:@selector(createTimmer) 
                            toTarget:self withObject:nil];
   ...

}

When I debug, the method createTimer runs ok, but the method does timerRun not run?

回答1:

Just creating a timer doesn't start it running. You need to both create it and schedule it.

You're actually going to have to do slightly more work than that if you want it to run on a background thread. NSTimers attach to NSRunloops, which are the Cocoa form of an event loop. Each NSThread inherently has a a run loop but you have to tell it to run explicitly.

A run loop with a timer attached can run itself indefinitely but you probably don't want it to because it won't be managing autorelease pools for you.

So, in summary, you probably want to (i) create the timer; (ii) attach it to that thread's run loop; (iii) enter a loop that creates an autorelease pool, runs the run loop for a bit and then drains the autorelease pool.

Code will probably look like:

// create timer
timer = [NSTimer timerWithTimeInterval:1.0 
                                target:self 
                              selector:@selector(timerRun) 
                              userInfo:nil 
                               repeats:YES];

// attach the timer to this thread's run loop
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

// pump the run loop until someone tells us to stop
while(!someQuitCondition)
{
    // create a autorelease pool
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    // allow the run loop to run for, arbitrarily, 2 seconds
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];

    // drain the pool
    [pool drain];
}

// clean up after the timer
[timer invalidate];


回答2:

You have to schedule a timer for it to run. They get attached to a run loop, which in turn updates the timer as necessary.

You can either change createTimer to

[NSTimer scheduledTimerWithTimeInterval:1.0 
                                   target:self 
                                 selector:@selector(timerRun) 
                                 userInfo:nil 
                                  repeats:YES];

or add

[[NSRunLoop currentRunLoop] addTimer:timer forModes:NSRunLoopCommonModes];


回答3:

The method signature that you use in scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: must have an argument for the NSTimer as it passes itself as an argument.

You should change your message signature to:

(void)timerRun:(NSTimer *)timer;

You don't need to do anything with the argument, but it should be there. Also in createTimer the selector will become @selector(timerRun:) as it now accepts an argument:

timer = [NSTimer timerWithTimeInterval:1.0 
                              target:self 
                            selector:@selector(timerRun:) 
                            userInfo:nil 
                             repeats:YES];


标签: ios nstimer