题 我如何使用NSTimer?


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


345
2017-09-19 17:25


起源


我得到了参数信息 pravinmagdum.wordpress.com/2010/12/30/how-to-use-nstimer 看看它..可能对你有所帮助


答案:


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

对于您的情况,定时器编程主题文章可能是最有用的,而线程主题是相关的,但不是与所记录的类最直接相关。如果你看一下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 out实例变量(例如,如果多次调用使计时器失效的方法并且实例变量未设置为 nil 和 NSTimer 实例已被解除分配,它将抛出异常)。

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

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


617
2017-09-19 17:58



Okk,有一个问题,我将把每两秒执行一次的代码放入什么? - lab12
你过去了 YES 对于 repeats: 你打电话时 scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:。如果你这样做,那么一定要保持对它的引用 NSTimer 实例(由方法返回)并按照上面详述的内存管理点。 - Alex Rozanski
不,我会把我的代码放在哪里,每2秒启动一次?例如,假设我希望它每2秒发出一次哔声。我在哪里可以发出哔声代码..? - lab12
在您指定的方法中 target 和 selector。例如,如果您的目标是 self 而选择器是 timerMethod:,计时器触发时调用的方法是 timerMethod: 在...上定义 self。然后,您可以在该方法中放置您想要的任何代码,并且只要计时器触发,就会调用该方法。请注意,计时器触发时调用的方法(您传入的方法) selector:)只能接受一个参数(当被调用时是一个指针 NSTimer 实例)。 - Alex Rozanski
+1提及计时器的内存管理方面 - DonnaLea


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

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

NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
                      target: self
                      selector:@selector(onTick:)
                      userInfo: nil repeats:NO];
  • 如果将重复次数设置为NO,则计时器将在运行选择器之前等待2秒钟,之后它将停止;
  • 如果重复:是,则计时器将立即启动,并将每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:方法如下所示:

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

332
2017-09-19 17:58



好的,但你看我想降低我的应用程序的透明度,所以我不知道如何应用NSTimer - lab12
jeez,今天这些人..从我这里投票,因为你从一开始就没有明确指出,让我们徒劳无功! - Woofy
你没有写白白。这是好消息! - willc2
在方法2中,“自行计时器”,如何在需要时停止计时器? - Satyam
@Satyamsvv,你可以通过调用来停止计时器,说另一种方法:[timer invalidate]; timer = nil; - Kimpoy


像这样的东西:

NSTimer *timer;

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

59
2017-09-19 17:30



仍然强劲...... 2014年! - Muruganandham K


#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

5
2017-12-17 17:49



不知怎的,它创造了保留周期,所以 MyViewController 永远不会被解除分配。 - Darrarski


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

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

5
2018-03-24 07:20



但它在背景中不起作用 - Jignesh B
你能给出可以在后台运行的脚本吗? - Jignesh B
你在哪里写的? - Mohit
@JigneshB这个答案只是关于如何使用NSTimer而不是在后台使用它 - Mohit
我在后台方法中写道,即 - (void)applicationDidEnterBackground:(UIApplication *)application {} - Jignesh B


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

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

添加一个小时组件工作得很好,不需要午夜测试(链接


2
2017-10-25 23:37