J'ai un problème complexe pour décrire si mal savez-le et résumez simplement ce que je tente de faire. Je cherche à "être averti" lorsque le temps de la barre d'état change afin que je puisse recalculer le temps jusqu'à ce que ce soit. Je suis actuellement en train de calculer le temps jusqu'à juste bien, mais il y a cette fenêtre de 1 minute où mes calculs et où l'horodatage ne correspondent pas ... Tout dépend de quand ils ont ouvert l'application, par rapport à l'horloge "secondes" de l'iPhone. Ils l'ont ouvert. p>
Donc en bref, pouvons-nous détecter lorsque la minute change sur la barre d'état? Si oui, comment? P>
Merci! P>
8 Réponses :
Il n'y a pas de notification de ce type, je suppose donc que vous devez écrire du code qui sondre le temps assez souvent. Je créerais une source de boucle d'exécution pour cela, ajoutez-la aux modes courants et je la laisserais vérifier si le courant nstimerinterval code> puisque votre date de référence préférée est supérieure ou égale à un
NSTIMEINTERVAL < / code> qui contient l'intervalle de temps pour la prochaine minute complète. P>
C'est ce que je ferais: p>
Lorsque l'application est lancée, je démarrerais une minuterie qui mettrait à jour chaque seconde pour vérifier lorsque l'heure change. P>
La première fois que je trouve un changement de temps, j'invaliderais cette minuterie et commencerais celui qui déclencherait chaque minute. P>
Cette minuterie minute serait synchronisée avec un délai non supérieur à une seconde avec l'horloge de la barre d'état. P>
Même plus simple que la réponse de Emilio - lorsque votre affichage se charge (ou lorsque vous souhaitez déclencher l'événement), vérifiez simplement la partie secondaire de la date actuelle (par exemple, avec NSCalendar), planifiez une minuterie qui ira dans 60 Currentseconds (que sera la minute suivante, zéro secondes) et enfin, planifiez une nouvelle minuterie qui tire chaque 60 secondes. P>
C'est la réponse la plus intelligente.
Cela a fonctionné pour moi mais je devais faire 61 currentsecondes
Basé sur la suggestion de @ MJA:
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents *components = [calendar components:NSSecondCalendarUnit fromDate:[NSDate date]]; NSInteger currentSecond = [components second]; //+1 to ensure we fire right after the minute change NSDate *fireDate = [[NSDate date] dateByAddingTimeInterval:60 - currentSecond + 1]; NSTimer *timer = [[NSTimer alloc] initWithFireDate:fireDate interval:60 target:self selector:@selector(YOURSELECTORHERE) userInfo:nil repeats:YES]; [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
basé sur l'échantillon de code @ SG1 mais à Swift:
// Calculate fireDate on every minute's first second let now: Date = Date() let calendar: Calendar = Calendar.current let currentSeconds: Int = calendar.component(.second, from: now) // Init timer self.timer = Timer( fire: now.addingTimeInterval(Double(60 - currentSeconds + 1)), interval: 60 /*seconds*/, repeats: true, block: { (t: Timer) in self.sendNotification() }) // Start timer RunLoop.main.add(self.timer, forMode: RunLoopMode.defaultRunLoopMode) private func sendNotification(){ ... }
J'ai creusé dans ceci et trouvé le calendrier Exemple: p> comme autre réponse note, un tampon semble être nécessaire pour s'assurer que cela est tiré après la minute de la minute (vitale si vous présentez le temps à chaque minute. Par exemple), d'où le .NextDate (après: correspondant: correspondantPolicy: répétéeTimepolicy: direction :) code> méthode, supprimant la nécessité de faire des calculs dans le code de l'application.
NextMinute.Advanced (par: 0.1) code> (100 ms). Je n'ai trouvé aucune documentation sur exactement combien, mais la 100 ms semble bien dans mon bref test. P> p>
Cela fonctionne parfaitement pour moi, où avez-vous trouvé la documentation? Parce que je ne comprends pas comment cela fonctionne
À mon avis, c'est la réponse la plus précise. Excellent travail
@FarrasDoko Comment ça marche est qu'il crée une date date code> représentant le changement de minute suivant (c'est-à-dire la date suivante avec secondes == 0). Ensuite, cela crée une minuterie pour tirer sur cette date
(code> (Eh bien, plus 0,1 seconde pour vous assurer que ce n'est pas manqué dans le cas où cette méthode a été appelée à droite de la minute), puis tirez tous les 60 secondes par la suite.
Voici un autre moyen de déclencher une minuterie à l'aide de code> planchedTimer code>, cette approche utilise une fonction qui s'appelle récurremment elle-même une fois que la minuterie est tirée au lieu d'utiliser des intervalles de 60s fixes.
private var timer: Timer? private func setupTimer() { let calendar: Calendar = .current let seconds = calendar.component(.second, from: Date()) timer = Timer.scheduledTimer( withTimeInterval: 60 - TimeInterval(seconds), repeats: false ) { [weak self] timer in self?.timer = nil // Do something, eg. update UI self?.setupTimer() } }
Basé sur la réponse de @ Stefanlindbohm, mais sans une référence forte à auto code> et d'arrêter la minuterie à la prochaine cuisson si l'objet a été traité:
var zeroSeconds = DateComponents()
zeroSeconds.second = 0
guard let nextMinute = Calendar(identifier: .gregorian).nextDate(after: Date(), matching: zeroSeconds, matchingPolicy: .nextTime, direction: .forward) else {
// This should not happen since there should always be a next minute
return
}
var timer: Timer?
timer = Timer(fire: nextMinute.advanced(by: 0.1), interval: 60, repeats: true) { [weak self] _ in
guard let self = self else {
timer?.invalidate()
timer = nil
return
}
// Do your work here, using `self`.
}
if let timer = timer {
RunLoop.main.add(timer, forMode: .default)
}