Risposte:
Innanzi tutto, vorrei attirare la vostra attenzione sulla documentazione Cocoa / CF (che è sempre un ottimo primo approdo). I documenti di Apple hanno una sezione nella parte superiore di ogni articolo di riferimento chiamato "Guide companion", che elenca le guide per l'argomento documentato (se presente). Ad esempio, con NSTimer
, la documentazione elenca due guide companion:
Per la tua situazione, l'articolo Argomenti di programmazione del timer è probabilmente il più utile, mentre gli argomenti di threading sono correlati ma non più direttamente correlati alla classe che viene documentata. Se dai un'occhiata all'articolo Argomenti di programmazione del timer, è diviso in due parti:
Per gli articoli che assumono questo formato, c'è spesso una panoramica della classe e del suo uso, e poi del codice di esempio su come usarlo, in questo caso nella sezione "Uso dei timer". Ci sono sezioni su "Creazione e pianificazione di un timer", "Arresto di un timer" e "Gestione della memoria". Dall'articolo, la creazione di un timer programmato e non ripetibile può essere eseguita in questo modo:
[NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(targetMethod:)
userInfo:nil
repeats:NO];
Ciò creerà un timer che viene attivato dopo 2,0 secondi e chiama targetMethod:
su self
di un argomento, che è un puntatore alla NSTimer
istanza.
Se vuoi quindi esaminare più dettagliatamente il metodo, puoi fare riferimento ai documenti per ulteriori informazioni, ma c'è anche una spiegazione intorno al codice.
Se si desidera arrestare un timer che si ripete (o interrompere un timer che non si ripete prima che si attivi), è necessario mantenere un puntatore NSTimer
all'istanza creata; spesso questa dovrà essere una variabile di istanza in modo da poter fare riferimento ad essa in un altro metodo. È quindi possibile chiamare invalidate
l' NSTimer
istanza:
[myTimer invalidate];
myTimer = nil;
E 'anche buona norma nil
la variabile di istanza (ad esempio se il metodo che invalida il timer è chiamato più di una volta e la variabile di istanza non è stata impostata per nil
e laNSTimer
istanza è stata deallocata, genererà un'eccezione).
Nota anche il punto sulla gestione della memoria nella parte inferiore dell'articolo:
Poiché il ciclo di esecuzione mantiene il timer, dal punto di vista della gestione della memoria non è in genere necessario mantenere un riferimento a un timer dopo averlo pianificato . Dal momento che il timer viene passato come argomento quando si specifica il suo metodo come selettore, è possibile invalidare un timer ripetuto quando appropriato all'interno di quel metodo . In molte situazioni, tuttavia, si desidera anche l'opzione di invalidare il timer, forse anche prima che inizi. In questo caso, è necessario mantenere un riferimento al timer, in modo da poter inviare un messaggio non valido ogni volta che è necessario. Se si crea un timer non programmato (consultare "Timer non programmati"), è necessario mantenere un riferimento forte al timer (in un ambiente contato da riferimenti, lo si conserva) in modo che non venga deallocato prima di utilizzarlo.
YES
per repeats:
quando chiami scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
. Se lo fai, assicurati di mantenere un riferimento NSTimer
all'istanza (viene restituito dal metodo) e segui il punto su Gestione della memoria come ho dettagliato sopra.
target
e selector
. Ad esempio, se il tuo obiettivo è self
e il selettore è timerMethod:
, il metodo chiamato quando il timer scatta è timerMethod:
definito su self
. È quindi possibile inserire qualsiasi codice desiderato in quel metodo e il metodo verrà chiamato ogni volta che scatta il timer. Si noti che il metodo chiamato quando viene attivato il timer (che si passa come selector:
) può accettare solo un argomento (che quando chiamato è un puntatore NSTimer
all'istanza).
self
"
ci sono un paio di modi per usare un timer:
1) timer programmato e utilizzo del selettore
NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
target: self
selector:@selector(onTick:)
userInfo: nil repeats:NO];
Come nota a margine, invece di utilizzare un timer che non si ripete e chiama il selettore dopo un intervallo specificato, è possibile utilizzare una semplice istruzione come questa:
[self performSelector:@selector(onTick:) withObject:nil afterDelay:2.0];
questo avrà lo stesso effetto del codice di esempio sopra; ma se vuoi chiamare il selettore ogni ennesima volta, usi il timer con ripetizioni: SÌ;
2) timer autoprogrammato
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) timer non programmato e utilizzo dell'invocazione
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 successivamente, avvia il timer manualmente ogni volta che è necessario in questo modo:
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer: t forMode: NSDefaultRunLoopMode];
E come nota, onTick: il metodo è simile al seguente:
-(void)onTick:(NSTimer *)timer {
//do smth
}
Qualcosa come questo:
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
non viene mai deallocato.
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(timerCalled) userInfo:nil repeats:NO];
-(void)timerCalled
{
NSLog(@"Timer Called");
// Your Code
}
Le risposte mancano di un orario specifico del giorno qui è l'ora successiva:
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];
Ovviamente, sostituisci "doRefresh" con il metodo desiderato per la tua classe
provare a creare l'oggetto calendario una volta e rendere allUnits statico per efficienza.
l'aggiunta di un componente all'ora funziona perfettamente, non è necessario un test di mezzanotte ( link )