342

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

4

6 回答 6

614

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

对于您的情况,Timer Programming Topics 文章可能是最有用的,而 threading 主题与所记录的类相关但不是最直接相关的。如果您查看 Timer Programming Topics 文章,它分为两部分:

  • 计时器
  • 使用定时器

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

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

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

如果您想更详细地了解该方法,您可以参考文档以获取更多信息,但也有围绕代码的解释。

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

[myTimer invalidate];
myTimer = nil;

删除实例变量也是一种很好的做法nil(例如,如果多次调用使计时器无效的方法并且尚未将实例变量设置为nil并且NSTimer实例已被释放,它将引发异常)。

还要注意文章底部关于内存管理的一点:

因为运行循环维护计时器,所以从内存管理的角度来看,通常不需要在您安排好计时器后保留对计时器的引用。由于当您将计时器的方法指定为选择器时,计时器作为参数传递,因此您可以在该方法中适当时使重复计时器无效。然而,在许多情况下,您还需要使计时器无效的选项——甚至可能在它开始之前。在这种情况下,您确实需要保留对计时器的引用,以便您可以在适当的时候向其发送无效消息. 如果您创建了一个未调度的计时器(请参阅“未调度的计时器”),那么您必须维护对计时器的强引用(在引用计数环境中,您保留它),以便在使用它之前不会释放它。

于 2009-09-19T17:58:34.060 回答
330

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

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

NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
                      target: self
                      selector:@selector(onTick:)
                      userInfo: nil repeats:NO];
  • 如果将重复设置为 NO,计时器将在运行选择器之前等待 2 秒,然后停止;
  • 如果重复:YES,计时器将立即启动,并每 2 秒重复调用一次选择器;
  • 要停止计时器,您调用计时器的 -invalidate 方法:[t invalidate];

作为旁注,您可以使用这样的简单语句,而不是使用不重复并在指定间隔后调用选择器的计时器:

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

这将与上面的示例代码具有相同的效果;但是如果你想每 n 次调用一次选择器,你可以使用带有 repeats: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
}
于 2009-09-19T17:58:50.603 回答
59

像这样的东西:

NSTimer *timer;

    timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
                     target: self
                     selector: @selector(handleTimer:)
                     userInfo: nil
                     repeats: YES];
于 2009-09-19T17:30:37.050 回答
5
#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
于 2013-12-17T17:49:17.813 回答
5
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(timerCalled) userInfo:nil repeats:NO];

-(void)timerCalled
{
     NSLog(@"Timer Called");
     // Your Code
}
于 2014-03-24T07:20:07.007 回答
2

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

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

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

于 2013-10-25T23:37:26.467 回答