Comment puis-je créer un NSTimer sur un thread d'arrière-plan?
J'ai une tâche qui doit être effectuée à des intervalles de 1 seconde. Actuellement, j'ai un NSTimer feu à plusieurs reprises toutes les 1 sec. Comment puis-je avoir la minuterie d'incendie dans un thread d'arrière-plan (non UI thread)?
J'ai pu avoir les NSTimer le feu sur le thread principal, puis utilisez NSBlockOperation d'envoyer un thread d'arrière-plan, mais je me demandais si il existe un moyen plus efficace de le faire.
Vous devez vous connecter pour publier un commentaire.
La minuterie doivent être installés dans une course boucle d'exploitation sur une déjà en cours d'exécution thread d'arrière-plan. Ce thread devrait continuer à l'exécution de l'exécution de la boucle pour avoir la minuterie en fait le feu. Et pour que le thread d'arrière-plan pour continuer à être en mesure de tirer d'autres événements de la minuterie, il faut générer un nouveau thread pour en fait de gérer les événements de toute façon (en supposant, bien sûr, que le traitement que vous faites prend beaucoup de temps).
Pour ce qu'il vaut, je pense que la manipulation événements de la minuterie en lançant un nouveau thread à l'aide de Grand Central Dispatch ou
NSBlockOperation
est parfaitement raisonnable de l'utilisation de votre thread principal.Si vous avez besoin de cette sorte de minuteries encore exécuter lorsque vous faites défiler votre point de vue (ou les cartes), vous devez planifier sur différents exécuter en mode boucle. Remplacer votre minuterie:
Avec celui-ci:
Pour plus de détails, consultez cet article de blog: L'événement de suivi des arrêts de NSTimer
EDIT :
deuxième bloc de code, le NSTimer s'exécute toujours sur le thread principal, toujours sur le même parcours en boucle comme le scrollviews. La différence, c'est la course de la boucle mode. Vérifiez le blog pour une explication claire.
let timer = NSTimer.init(timeInterval: 0.1, target: self, selector: #selector(AClass.AMethod), userInfo: nil, repeats: true)
ajoutez Ensuite le minuteur:NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
Si vous voulez aller pure PGCD et utiliser une dépêche de source, Apple a un exemple de code pour cela dans leurs La Simultanéité Guide De Programmation:
Swift 3:
Vous pouvez mettre en place votre un deuxième événement de minuterie à l'aide d'un code comme le suivant:
faire assurez-vous de stocker et de libérer votre minuterie de fait, bien sûr. Ci-dessus vous donne un 1/10e de seconde de marge de manœuvre sur le tir de ces événements, ce qui peut se resserrer si vous le souhaitez.
invalidate
méthode. Vais-je obtenir un comportement similaire à l'aide dedispatch_suspend()
oudispatch_source_cancel()
? Sont à la fois nécessaires?dispatch_resume()
sera en pause et de reprendre une dépêche de la minuterie de ce genre. L'Invalidation avant le prélèvement se fait à l'aide dedispatch_source_cancel()
et puisdispatch_release()
(ce dernier peut ne pas être nécessaire pour l'ARC des applications compatibles sur certaines versions de système d'exploitation).Cela devrait fonctionner,
Il répète une méthode toutes les 1 seconde dans un contexte de file d'attente, sans l'aide de NSTimers 🙂
Si vous êtes dans la file d'attente principale et que vous voulez l'appeler la méthode ci-dessus, vous pouvez le faire de sorte à ce que le fond de la file d'attente avant de se lancer 🙂
Espère que cela aide
dispatch_source
minuterie si vous souhaitez utiliser le PGCD de puissance de cette chose.methodToRepeatEveryOneSecond
méthode de la classe a de le redémarrer à nouveau. Donc, si vous voulez l'arrêter, on avait mis une condition au-dessus de ladispatch_queue_t ...
ligne pour faire un retour si vous ne voulez pas continuer.Pour swift 3.0
Tikhonv réponse n'explique pas trop. Ici, ajoute un peu de ma compréhension.
À faire les choses à court d'abord, voici le code. Il est DIFFÉRENTS de Tikhonv du code à l'endroit où j'ai créer le minuteur. J'ai créer le minuteur à l'aide de constructeur et l'ajouter dans la boucle. Je pense que le scheduleTimer fonction ajouter le minuteur sur le thread principal de l'RunLoop. Donc, il est préférable de créer de la minuterie en utilisant le constructeur.
Créer Une File D'Attente
Tout d'abord, créez une file d'attente pour faire de la minuterie s'exécuter en arrière-plan et de les stocker en tant que liste de propriétés de la classe afin de le réutiliser pour arrêter la minuterie. Je ne suis pas sûr si nous devons utiliser la même file d'attente pour démarrer et arrêter, la raison pour laquelle je l'ai fait c'est parce que j'ai vu un message d'avertissement ici.
J'ai donc décidé de stocker la file d'attente et d'utiliser la même file d'attente pour le compte à rebours pour éviter les problèmes de synchronisation.
Également créer un vide minuterie et stockée dans la variable de classe ainsi. Le rendre facultatif de sorte que vous pouvez arrêter la minuterie et réglez à néant.
Démarrer La Minuterie
Pour démarrer la minuterie, le premier appel asynchrone à partir de DispatchQueue. Alors c'est une bonne pratique de vérifier d'abord si le compte à rebours est déjà commencé. Si la minuterie variable n'est pas nulle, alors invalidate() et mis à néant.
La prochaine étape est d'obtenir le courant RunLoop. Parce que nous l'avons fait dans le bloc de file d'attente, nous avons créé, il pourra obtenir les RunLoop pour le fond de la file d'attente que nous avons créé auparavant.
Créer de la minuterie. Ici, au lieu d'utiliser scheduledTimer, il suffit d'appeler le constructeur de la minuterie et de passer à ce que la propriété que vous voulez pour la minuterie comme timeInterval, cible, sélecteur, etc.
Ajouter à la création de la minuterie à la RunLoop. L'exécuter.
Voici une question à propos de l'exécution de la RunLoop. Selon la documentation ici, dit-il, il a effectivement commence une boucle infinie qui traite des données à partir de l'exécution de la boucle sources d'entrée et les minuteries.
De Déclenchement Minuterie
Mettre en œuvre la fonction normale. Lorsque cette fonction est appelée, elle est appelée, en vertu de la file d'attente par défaut.
La fonction ci-dessus est à utiliser pour imprimer le nom de la file d'attente. Si jamais vous vous inquiétez pas si il a été en cours d'exécution sur la file d'attente, vous pouvez l'appeler pour vérifier.
Arrêter La Minuterie
Arrêter la minuterie est facile, appel valider() et réglez la minuterie variable stockée à l'intérieur de la classe à néant.
Ici, je suis en cours d'exécution en vertu de la file d'attente à nouveau. En raison de l'avertissement ici j'ai décidé de courir toute la minuterie du code connexe en vertu de la file d'attente pour éviter les conflits.
Questions liées à la RunLoop
Je suis en quelque sorte un peu confus sur si nous avons besoin d'arrêter manuellement le RunLoop ou pas. Selon la documentation, il semble que, lorsque aucun des minuteries attaché à elle, alors elle sort immédiatement. Alors, quand nous avons l'arrêt de la minuterie, il doit existe lui-même. Cependant, à la fin de ce document, il a dit aussi:
J'ai essayé la solution ci-dessous qui sont fournis dans la documentation pour une garantie de terminer la boucle. Cependant, la minuterie ne se déclenche pas après que j'ai changer .run() pour le code ci-dessous.
Ce que je pense, c'est qu'il pourrait être sûr pour que l'aide .run() sur iOS. Parce que la documentation indique que macOS est d'installer et de retirer d'autres sources d'entrée nécessaires pour traiter les demandes ciblant le récepteur du fil. Donc iOS pourrait être bien.
Timer
est lié à unRunLoop
qui est lié à un fil, pas à une file d'attente.Mon Swift 3.0 solution pour iOS 10+,
timerMethod()
sera appelé dans le fond de la file d'attente.Swift seulement (mais peut probablement être modifié pour une utilisation avec Objective-C)
Découvrez
DispatchTimer
de https://github.com/arkdan/ARKExtensions, qui "Exécute une fermeture sur l'expédition de la file d'attente, avec des intervalles de temps spécifiés, pour un nombre spécifié de fois (en option). "Aujourd'hui, après 6 ans, j'ai essayer de faire la même chose, ici, est-il une alternative soltion: PGCD ou NSThread.
Minuteries fonctionnent en conjonction avec exécuter des boucles, un thread runloop peut se faire à partir du thread seulement, donc, la clé est que le programmateur dans le fil.
Sauf le thread principal de l'runloop, runloop devrait démarrer manuellement; il devrait y avoir certains événements de la poignée en cours d'exécution runloop, comme à rebours, sinon runloop seront de sortie, et nous pouvons l'utiliser pour sortir d'un runloop si la minuterie est la seule source de l'événement: invalider la minuterie.
Le code suivant est Swift 4:
Solution 0: PGCD
Minuterie a une forte référence à la cible, et runloop a une forte référence à rebours, après le timer d'invalider, il la libération de la cible, afin de garder la faiblesse de référence dans la cible et de l'invalider dans le moment approprié pour quitter runloop(et puis la sortie de thread).
Remarque: comme l'optimisation,
sync
fonction deDispatchQueue
appelle le bloc sur le thread en cours lorsque cela est possible. En fait, vous exécutez le code ci-dessus dans le thread principal, un chronomètre est déclenché dans le thread principal, donc ne l'utilisez passync
fonction, sinon la minuterie n'est pas tiré sur le fil que vous voulez.Vous pourrait nommer le thread de suivre son activité en pause le programme en cours d'exécution dans Xcode. Dans PGCD, utilisation:
Solution 1: Thread
Nous pourrions utiliser NSThread directement. N'ayez pas peur, le code est facile.
Solution 2: Sous-Classe De Thread
Si vous souhaitez utiliser le Thread sous-classe:
Remarque: ne pas ajouter de la minuterie dans l'init, sinon, la minuterie est d'ajouter à init de l'appelant du thread runloop, pas ce thread runloop, par exemple, vous exécutez le code suivant dans le thread principal, si
TimerThread
ajouter un timer dans la méthode init, la minuterie sera prévue pour l'thread principal est runloop, pas timerThread de runloop. Vous pouvez le vérifier entimerMethod()
journal.P. S Sur
Runloop.current.run()
, son document suggèrent de ne pas appeler cette méthode si nous voulons runloop de résilier, de l'utilisationrun(mode: RunLoopMode, before limitDate: Date)
, en faitrun()
à plusieurs reprises appeler cette méthode dans le NSDefaultRunloopMode, ce que la mode? Plus de détails dans runloop et du fil.Si vous voulez que votre NSTimer pour s'exécuter en arrière-plan, procédez de la manière suivante-
Que c'est