提问



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

最佳参考


首先,我想提请你注意Cocoa/CF文档(它始终是一个很好的第一个停靠点).Apple文档在每篇参考文章的顶部都有一个名为Companion Guides的部分,其中列出了记录的主题(如果存在)。例如,NSTimer,文档列出了两个配套指南:[24]



  • Cocoa的计时器编程主题

  • 线程编程指南



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



  • 计时器

  • 使用计时器



对于采用这种格式的文章,通常会对类的概述及其用途进行概述,然后在如何使用的示例代码中使用它,在本例中为使用计时器有关创建和调度定时器,停止定时器和内存管理的部分。从文章中,创建一个预定的,非重复的定时器可以这样做:


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


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


如果您想在该方法中查看更多详细信息,可以参考文档以获取更多信息,但也有关于代码的解释。


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


[myTimer invalidate];
myTimer = nil;


nil实例变量也是一种好习惯(例如,如果你的方法使定时器失效多次被调用而且实例变量没有被设置为nil和[[]] NSTimer实例已被解除分配,它将抛出异常)。


另请注意文章底部的内存管理要点:



  因为运行循环维护计时器,从内存管理的角度来看通常不需要在计划后保留对计时器的引用。因为计时器作为参数传递时您将其方法指定为选择器,您可以在该方法中适当地使重复计时器无效。但是,在许多情况下,您还需要使计时器无效的选项 - 甚至可能在它启动之前。< strong>在这种情况下,您需要保留对计时器的引用,以便您可以在适当的时候向其发送无效消息。如果您创建一个未计划的计时器(请参阅未计划的计时器),那么您必须保持对计时器的强引用(在引用计数环境中,保留它),以便在使用它之前不会释放它。


其它参考1


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


1)预定计时器&使用选择器


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



  • 如果将重复次数设置为NO,则计时器将在运行选择器之前等待2秒,之后将停止;

  • 如果重复:是,则计时器将立即启动,并将每2秒重复调用一次选择器;

  • 停止计时器s -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:方法如下所示:


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

其它参考2


像这样的东西:


NSTimer *timer;

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

其它参考3


#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

其它参考4


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

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

其它参考5


答案缺少一个特定的时间计时器,这是在下一个小时:


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保持静态以提高效率。


添加一个小时组件工作正常,不需要午夜测试(链接)