Respostas:
Em primeiro lugar, 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 na parte superior de cada artigo de referência chamada "Guias complementares", que lista os guias para o tópico que está sendo documentado (se houver algum). Por exemplo, com NSTimer
, a documentação lista dois guias complementares:
Para sua situação, o artigo Tópicos de programação do timer provavelmente será o mais útil, enquanto os tópicos de encadeamento estão relacionados, mas não os mais diretamente relacionados à classe que está sendo documentada. Se você der uma olhada no artigo Tópicos de programação do timer, ele está dividido em duas partes:
Para artigos que usam esse formato, geralmente há uma visão geral da classe e para que ela é usada e, em seguida, alguns exemplos de código de como usá-la, neste caso na seção "Usando temporizadores". Existem seções em "Criando e agendando um timer", "Parando um timer" e "Gerenciamento de memória". A partir do artigo, a criação de um cronômetro agendado e sem repetição pode ser feita da seguinte maneira:
[NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(targetMethod:)
userInfo:nil
repeats:NO];
Isto irá criar um temporizador que é acionado após 2,0 segundos e chama targetMethod:
a self
com um argumento, que é um ponteiro para a NSTimer
instância.
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ê deseja interromper um cronômetro que seja repetido (ou interromper um cronômetro que não se repita antes que ele seja acionado), será necessário manter um ponteiro para a NSTimer
instância que foi criada; frequentemente, isso precisará ser uma variável de instância para que você possa se referir a ela em outro método. Você pode chamar invalidate
a NSTimer
instância:
[myTimer invalidate];
myTimer = nil;
Também é uma boa prática nil
extrair 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 nil
e a NSTimer
instância tiver sido desalocada, será lançada uma exceção).
Observe também o ponto sobre Gerenciamento de memória na parte inferior do artigo:
Como o loop de execução mantém o cronômetro, da perspectiva do gerenciamento de memória , normalmente não há necessidade de manter uma referência a um cronômetro depois que você o agendou . Como o cronômetro é passado como argumento quando você especifica seu método como seletor, você pode invalidar um cronômetro de repetição quando apropriado dentro desse método . Em muitas situações, no entanto, você também deseja a opção de invalidar o cronômetro - talvez 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 “Temporizadores não programados”), deverá manter uma forte referência ao cronômetro (em um ambiente contado por referência, você o mantém) para que ele não seja desalocado antes de usá-lo.
YES
para repeats:
quando você chamar scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
. Se você fizer isso, mantenha uma referência à NSTimer
instância (ela é retornada pelo método) e siga o ponto em Gerenciamento de memória, conforme detalhado acima.
target
e selector
. Por exemplo, se o seu destino é self
e o seletor é timerMethod:
, o método chamado quando o timer é acionado é timerMethod:
definido no self
. Você pode colocar o código que desejar nesse método, e o método será chamado sempre que o timer for acionado. Observe que o método chamado quando o timer é acionado (que você transmite como selector:
) pode receber apenas um argumento (que quando chamado é um ponteiro para a NSTimer
instância).
self
"
existem algumas maneiras de usar um timer:
1) cronômetro programado e usando o seletor
NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
target: self
selector:@selector(onTick:)
userInfo: nil repeats:NO];
Como uma observação lateral, em vez de usar um timer que não se repita e chama o seletor após um intervalo especificado, você pode 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 pela enésima vez, use o temporizador com repetições: YES;
2) temporizador auto-agendado
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) cronômetro 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:
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer: t forMode: NSDefaultRunLoopMode];
E, como observação, o método onTick: se parece com o seguinte:
-(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
MyViewController
nunca seja desalocado.
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 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];
Obviamente, substitua "doRefresh" pelo método desejado da sua classe
tente criar o objeto de calendário uma vez e torne allUnits uma estática para obter eficiência.
adicionar um componente de uma hora funciona perfeitamente, sem necessidade de um teste à meia-noite ( link )