Réponses:
Tout d'abord, je voudrais attirer votre attention sur la documentation Cocoa / CF (qui est toujours un excellent premier port d'escale). Les documents Apple ont une section en haut de chaque article de référence appelée "Guides d'accompagnement", qui répertorie les guides pour le sujet en cours de documentation (le cas échéant). Par exemple, avec NSTimer
, la documentation répertorie deux guides complémentaires:
Pour votre situation, l'article Timer Programming Topics est probablement le plus utile, tandis que les sujets de threading sont liés, mais pas les plus directement liés à la classe en cours de documentation. Si vous jetez un œil à l'article sur les rubriques de programmation du minuteur, il est divisé en deux parties:
Pour les articles qui prennent ce format, il y a souvent un aperçu de la classe et de son utilisation, puis un exemple de code sur la façon de l'utiliser, dans ce cas dans la section "Utilisation des minuteurs". Il y a des sections sur "Créer et planifier une minuterie", "Arrêter une minuterie" et "Gestion de la mémoire". À partir de l'article, la création d'une minuterie non répétitive planifiée peut être effectuée comme suit:
[NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(targetMethod:)
userInfo:nil
repeats:NO];
Cela va créer une minuterie qui est déclenché après 2,0 secondes et appelle targetMethod:
à self
avec un argument, qui est un pointeur vers l' NSTimer
instance.
Si vous souhaitez ensuite regarder plus en détail la méthode, vous pouvez vous référer aux documents pour plus d'informations, mais il y a aussi des explications autour du code.
Si vous souhaitez arrêter un minuteur qui se répète (ou arrêter un minuteur non répétitif avant qu'il ne se déclenche), vous devez conserver un pointeur sur l' NSTimer
instance qui a été créée; souvent, cela devra être une variable d'instance afin que vous puissiez vous y référer dans une autre méthode. Vous pouvez ensuite appeler invalidate
l' NSTimer
instance:
[myTimer invalidate];
myTimer = nil;
Il est également recommandé de nil
supprimer la variable d'instance (par exemple, si votre méthode qui invalide le temporisateur est appelée plusieurs fois et que la variable d'instance n'a pas été définie sur nil
et que l' NSTimer
instance a été désallouée, elle lèvera une exception).
Notez également le point sur la gestion de la mémoire au bas de l'article:
Étant donné que la boucle d'exécution maintient le minuteur, du point de vue de la gestion de la mémoire, il n'est généralement pas nécessaire de conserver une référence à un minuteur après l'avoir planifié . Étant donné que le minuteur est passé en argument lorsque vous spécifiez sa méthode en tant que sélecteur, vous pouvez invalider un minuteur répétitif lorsque cela est approprié dans cette méthode . Dans de nombreuses situations, cependant, vous souhaitez également l'option d'invalider le minuteur, peut-être même avant qu'il ne démarre. Dans ce cas, vous devez conserver une référence à la minuterie, afin de pouvoir lui envoyer un message d'invalidation chaque fois que cela est approprié.. Si vous créez un minuteur non planifié (voir «Minuteurs non planifiés»), vous devez conserver une référence forte au minuteur (dans un environnement compté par référence, vous le conservez) afin qu'il ne soit pas désalloué avant de l'utiliser.
YES
pour repeats:
quand tu appelles scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
. Si vous le faites, assurez-vous de conserver une référence à l' NSTimer
instance (elle est renvoyée par la méthode) et suivez le point sur la gestion de la mémoire comme je l'ai détaillé ci-dessus.
target
et selector
. Par exemple, si votre cible est self
et que le sélecteur l'est timerMethod:
, la méthode appelée lorsque le minuteur se déclenche est timerMethod:
définie sur le self
. Vous pouvez ensuite mettre le code que vous voulez dans cette méthode, et la méthode sera appelée chaque fois que le minuteur se déclenchera. Notez que la méthode appelée lorsque le minuteur se déclenche (que vous passez en tant que selector:
) ne peut prendre qu'un seul argument (qui, lorsqu'il est appelé, est un pointeur vers l' NSTimer
instance).
self
"
il existe deux façons d'utiliser une minuterie:
1) minuterie programmée et utilisation du sélecteur
NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
target: self
selector:@selector(onTick:)
userInfo: nil repeats:NO];
En guise de remarque, au lieu d'utiliser une minuterie qui ne se répète pas et appelle le sélecteur après un intervalle spécifié, vous pouvez utiliser une instruction simple comme celle-ci:
[self performSelector:@selector(onTick:) withObject:nil afterDelay:2.0];
cela aura le même effet que l'exemple de code ci-dessus; mais si vous voulez appeler le sélecteur une nième fois, vous utilisez la minuterie avec des répétitions: OUI;
2) minuterie auto-programmée
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) Minuterie non planifiée et utilisation de l'invocation
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];
et après cela, vous démarrez le minuteur manuellement chaque fois que vous en avez besoin comme ceci:
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer: t forMode: NSDefaultRunLoopMode];
Et comme note, la méthode onTick: ressemble à ceci:
-(void)onTick:(NSTimer *)timer {
//do smth
}
Quelque chose comme ça:
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
jamais n'est désalloué.
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(timerCalled) userInfo:nil repeats:NO];
-(void)timerCalled
{
NSLog(@"Timer Called");
// Your Code
}
Il manque une réponse à une heure précise de la journée, voici l'heure suivante:
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];
Bien sûr, remplacez "doRefresh" par la méthode souhaitée par votre classe
essayez de créer l'objet calendrier une fois et de rendre les allUnits statiques pour plus d'efficacité.
l'ajout d'un composant à l'heure fonctionne très bien, pas besoin de test à minuit ( lien )