我如何使用NSTimer?谁能给我一步一步的指导?


就像这样:

NSTimer *timer;

    timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
                     target: self
                     selector: @selector(handleTimer:)
                     userInfo: nil
                     repeats: YES];

首先,我想让您注意一下Cocoa/CF文档(这总是一个很好的第一步)。苹果文档在每篇参考文章的顶部都有一个叫做“Companion Guides”的部分,它列出了所记录主题的指南(如果存在的话)。例如,对于NSTimer,文档列出了两个配套指南:

可可定时器编程主题 线程编程指南

对于您的情况,定时器编程主题文章可能是最有用的,而线程主题与所记录的类相关,但不是最直接的相关。如果你看一看定时器编程主题的文章,它分为两部分:

计时器 使用定时器

对于采用这种格式的文章,通常有一个类的概述和它的用途,然后是一些关于如何使用它的示例代码,在本例中是“使用计时器”部分。有“创建和调度定时器”,“停止定时器”和“内存管理”部分。在本文中,可以这样创建一个定时的、不重复的计时器:

[NSTimer scheduledTimerWithTimeInterval:2.0
    target:self
    selector:@selector(targetMethod:)
    userInfo:nil
    repeats:NO];

这将创建一个定时器,在2.0秒后触发,并使用一个参数调用targetMethod: on self,这是一个指向NSTimer实例的指针。

如果你想更详细地了解这个方法,你可以参考文档获取更多信息,但是关于代码也有解释。

如果你想停止一个重复的计时器(或在它触发之前停止一个非重复的计时器),那么你需要保留一个指向已创建的NSTimer实例的指针;通常这需要是一个实例变量,以便您可以在另一个方法中引用它。然后你可以在NSTimer实例上调用invalidate:

[myTimer invalidate];
myTimer = nil;

这也是一个很好的实践,nil实例变量(例如,如果你的方法无效定时器被调用了不止一次,实例变量还没有被设置为nil, NSTimer实例已经被释放,它将抛出一个异常)。

还要注意文章末尾关于内存管理的观点:

Because the run loop maintains the timer, from the perspective of memory management there's typically no need to keep a reference to a timer after you’ve scheduled it. Since the timer is passed as an argument when you specify its method as a selector, you can invalidate a repeating timer when appropriate within that method. In many situations, however, you also want the option of invalidating the timer—perhaps even before it starts. In this case, you do need to keep a reference to the timer, so that you can send it an invalidate message whenever appropriate. If you create an unscheduled timer (see “Unscheduled Timers”), then you must maintain a strong reference to the timer (in a reference-counted environment, you retain it) so that it is not deallocated before you use it.


有几种使用计时器的方法:

1)定时定时器和使用选择器

NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
                      target: self
                      selector:@selector(onTick:)
                      userInfo: nil repeats:NO];

如果你将repeat设置为NO,计时器将在运行选择器之前等待2秒,之后它将停止; 如果重复:YES,计时器将立即启动,并将每2秒重复调用选择器; 要停止计时器,请调用计时器的-invalidate方法:[t invalidate];

作为旁注,与其使用不重复的计时器,并在指定的间隔后调用选择器,不如使用如下简单的语句:

[self performSelector:@selector(onTick:) withObject:nil afterDelay:2.0];

这将与上面的示例代码具有相同的效果;但如果你想每n次调用一次选择器,你可以使用重复的计时器:YES;

2)自动定时定时器

NSDate *d = [NSDate dateWithTimeIntervalSinceNow: 60.0];
NSTimer *t = [[NSTimer alloc] initWithFireDate: d
                              interval: 1
                              target: self
                              selector:@selector(onTick:)
                              userInfo:nil repeats:YES];

NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer:t forMode: NSDefaultRunLoopMode];
[t release];

这将创建一个计时器,该计时器将在您指定的自定义日期(在本例中为一分钟后)开始,并每一秒钟重复一次

3)计划外定时器&使用调用

NSMethodSignature *sgn = [self methodSignatureForSelector:@selector(onTick:)];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sgn];
[inv setTarget: self];
[inv setSelector:@selector(onTick:)];

NSTimer *t = [NSTimer timerWithTimeInterval: 1.0
                      invocation:inv 
                      repeats:YES];

在那之后,你可以手动启动计时器,就像这样:

NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer: t forMode: NSDefaultRunLoopMode];

注意,onTick: method看起来是这样的:

-(void)onTick:(NSTimer *)timer {
   //do smth
}

答案中缺少一个特定的时间,这里是下一个小时:

NSCalendarUnit allUnits = NSCalendarUnitYear   | NSCalendarUnitMonth |
                          NSCalendarUnitDay    | NSCalendarUnitHour  |
                          NSCalendarUnitMinute | NSCalendarUnitSecond;

NSCalendar *calendar = [[ NSCalendar alloc]  
                          initWithCalendarIdentifier:NSGregorianCalendar];

NSDateComponents *weekdayComponents = [calendar components: allUnits 
                                                  fromDate: [ NSDate date ] ];

[ weekdayComponents setHour: weekdayComponents.hour + 1 ];
[ weekdayComponents setMinute: 0 ];
[ weekdayComponents setSecond: 0 ];

NSDate *nextTime = [ calendar dateFromComponents: weekdayComponents ];

refreshTimer = [[ NSTimer alloc ] initWithFireDate: nextTime
                                          interval: 0.0
                                            target: self
                                          selector: @selector( doRefresh )
                                          userInfo: nil repeats: NO ];

[[NSRunLoop currentRunLoop] addTimer: refreshTimer forMode: NSDefaultRunLoopMode];

当然,用类所需的方法替换“doRefresh”

尝试创建一次日历对象,并使allUnits为静态的效率。

添加一小时组件就可以了,不需要午夜测试(链接)


#import "MyViewController.h"

@interface MyViewController ()

@property (strong, nonatomic) NSTimer *timer;

@end

@implementation MyViewController

double timerInterval = 1.0f;

- (NSTimer *) timer {
    if (!_timer) {
        _timer = [NSTimer timerWithTimeInterval:timerInterval target:self selector:@selector(onTick:) userInfo:nil repeats:YES];
    }
    return _timer;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}

-(void)onTick:(NSTimer*)timer
{
    NSLog(@"Tick...");
}

@end

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(timerCalled) userInfo:nil repeats:NO];

-(void)timerCalled
{
     NSLog(@"Timer Called");
     // Your Code
}