Como eu uso o NSTimer?

Como eu uso um NSTimer ? Alguém pode me dar instruções passo a passo?

Primeiramente, gostaria de chamar sua atenção para a documentação do Cocoa / CF (que é sempre um excelente primeiro ponto de escala). Os documentos da Apple têm uma seção no topo de cada artigo de referência chamado “Guias de Acompanhamento”, que lista guias para o tópico que está sendo documentado (se existir algum). Por exemplo, com o NSTimer , a documentação lista dois guias complementares:

  • Tópicos de programação do timer para o cacau
  • Guia de Programação de Threading

Para sua situação, o artigo Timer Programming Topics provavelmente será o mais útil, enquanto os tópicos de encadeamento estão relacionados, mas não são os mais diretamente relacionados à class que está sendo documentada. Se você der uma olhada no artigo Timer Programming Topics, ele será dividido em duas partes:

  • Temporizadores
  • Usando timeres

Para artigos que usam esse formato, geralmente há uma visão geral da class e para o que ela é usada e, em seguida, um exemplo de código sobre como usá-la, neste caso, na seção “Usando timeres”. Existem secções sobre “Criar e Agendar um Temporizador”, “Parar um Temporizador” e “Gestão de Memória”. A partir do artigo, a criação de um cronômetro agendado e não repetitivo pode ser feito assim:

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

Isso criará um timer triggersdo após 2,0 segundos e chamará targetMethod: em self com um argumento, que é um ponteiro para a instância do NSTimer .

Se você quiser examinar mais detalhadamente o método, consulte os documentos para obter mais informações, mas também há explicações sobre o código.

Se você quiser interromper um cronômetro que seja repetitivo (ou interromper um cronômetro que não seja de repetição antes que ele seja triggersdo), será necessário manter um ponteiro para a instância do NSTimer que foi criada; muitas vezes isso precisará ser uma variável de instância para que você possa consultá-la em outro método. Você pode então chamar invalidate na instância do NSTimer :

 [myTimer invalidate]; myTimer = nil; 

Também é uma boa prática remover a variável da instância (por exemplo, se o método que invalida o timer for chamado mais de uma vez e a variável da instância não tiver sido definida como nil e a instância do NSTimer tiver sido desalocada, ela emitirá uma exceção) .

Observe também o ponto no Gerenciamento de Memória na parte inferior do artigo:

Como o loop de execução mantém o timer, da perspectiva do gerenciamento de memory , normalmente não há necessidade de manter uma referência a um timer depois de agendá-lo . Como o timer é passado como um argumento quando você especifica seu método como um seletor, é possível invalidar um timer de repetição quando apropriado dentro desse método . Em muitas situações, no entanto, você também quer a opção de invalidar o cronômetro – talvez até mesmo antes de iniciar. Nesse caso, você precisa manter uma referência ao cronômetro, para poder enviar uma mensagem inválida sempre que apropriado . Se você criar um cronômetro não programado (consulte “Cronômetros não programados”), deverá manter uma referência forte ao cronômetro (em um ambiente de contagem de referência, você o mantém) para que ele não seja desalocado antes de usá-lo.

Existem algumas maneiras de usar um timer:

1) timer programado e usando o seletor

 NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0 target: self selector:@selector(onTick:) userInfo: nil repeats:NO]; 
  • se você definir repete para NO, o timer esperará 2 segundos antes de executar o seletor e depois disso ele irá parar;
  • se repetir: SIM, o timer iniciará imediatamente e repetirá a chamada do seletor a cada 2 segundos;
  • para parar o timer que você chama de método -invalidate do timer: [t invalidate];

Como uma nota lateral, em vez de usar um timer que não se repete e chama o seletor depois de um intervalo especificado, você poderia usar uma declaração simples como esta:

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

isso terá o mesmo efeito que o código de exemplo acima; mas se você quiser chamar o seletor a cada enésima vez, use o timer com repetições: YES;

2) timer auto-programado

 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]; 
  • isso criará um timer que iniciará a si mesmo em uma data personalizada especificada por você (nesse caso, após um minuto) e se repetirá a cada segundo

3) timer não programado e usando invocação

 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]; 

e depois disso, você inicia o timer manualmente sempre que precisar assim:

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

E, como nota, o método onTick: é assim:

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

Algo assim:

 NSTimer *timer; timer = [NSTimer scheduledTimerWithTimeInterval: 0.5 target: self selector: @selector(handleTimer:) userInfo: nil repeats: YES]; 
 #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 } 

As respostas estão faltando uma hora específica do dia timer aqui é na próxima hora:

 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]; 

Claro, substitua “doRefresh” pelo método desejado da sua class

tente criar o object de calendar uma vez e torne as allUnits uma estática para eficiência.

adicionar um componente à hora funciona muito bem, não há necessidade de um teste à meia-noite ( link )