Dans ce scénario, timerFunc () n'est jamais appelé. Qu'est-ce que je rate?
class AppDelegate: NSObject, NSApplicationDelegate {
var myTimer: NSTimer? = nil
func timerFunc() {
println("timerFunc()")
}
func applicationDidFinishLaunching(aNotification: NSNotification?) {
myTimer = NSTimer(timeInterval: 5.0, target: self, selector:"timerFunc", userInfo: nil, repeats: true)
}
}
Vous pouvez créer un minuteur programmé qui s’ajoute automatiquement au runloop et commence à se déclencher:
Swift 2
NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: "timerDidFire:", userInfo: userInfo, repeats: true)
Swift 3, 4, 5
Timer.scheduledTimer(withTimeInterval: 0.5, target: self, selector: #selector(timerDidFire(_:)), userInfo: userInfo, repeats: true)
Ou bien, vous pouvez conserver votre code actuel et ajouter la minuterie au runloop lorsque vous êtes prêt pour cela:
Swift 2
let myTimer = NSTimer(timeInterval: 0.5, target: self, selector: "timerDidFire:", userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(myTimer, forMode: NSRunLoopCommonModes)
Swift 3, 4, 5
let myTimer = Timer(timeInterval: 0.5, target: self, selector: #selector(timerDidFire(_:)), userInfo: nil, repeats: true)
RunLoop.current.add(myTimer, forMode: RunLoop.Mode.common)
j'utilise une approche similaire à Luke. Seulement une mise en garde pour les gens qui sont des puristes "méthodes privées":
NE PAS rendre le rappel privé dans Swift.
Si vous écrivez:
private func timerCallBack(timer: NSTimer){
..
tu auras:
timerCallBack:]: sélecteur non reconnu envoyé à l'instance ... Application en cours de fermeture en raison d'une exception non interceptée 'NSInvalidArgumentException'
Les NSTimer ne sont pas programmés automatiquement, sauf si vous utilisez NSTimer.scheduledTimerWithTimeInterval
:
myTimer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "timerFunc", userInfo: nil, repeats: true)
Comme Drewag et Ryan l'ont souligné, vous devez créer un chronomètre programmé (ou le programmer vous-même). Le plus simple est de le créer déjà programmé avec:
myTimer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "timerFunc:", userInfo: nil, repeats: true)
Vous devez également modifier votre définition de timerFunc (et le sélecteur associé) pour prendre un argument et se terminer par un ':'
func timerFunc(timer:NSTimer!) {
...
}
Pour Swift
var timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(ViewController.updateTimer), userInfo: nil, repeats: true);
RunLoop.current.add(timer, forMode: RunLoopMode.commonModes)
Syntaxe Swift 3.0 pour la chose en boucle d’exécution:
RunLoop.current.add(myTimer, forMode: .commonModes)
C'est un peu de code, qui montre comment appeler une fonction (en différé) avec AND sans paramètre.
Utilisez ceci dans un nouveau projet en xCode (singleViewApplication) et placez le code dans le viewController standard:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: Selector("delayedFunctionWithoutParameter:"), userInfo: nil, repeats: false)
let myParameter = "ParameterStringOrAnyOtherObject"
NSTimer.scheduledTimerWithTimeInterval(4.0, target: self, selector: Selector("delayedFunctionWithParameter:"), userInfo: myParameter, repeats: false)
}
// SIMPLE TIMER - Delayed Function Call
func delayedFunctionWithoutParameter(timer : NSTimer) {
print("This is a simple function beeing called without a parameter passed")
timer.invalidate()
}
// ADVANCED TIMER - Delayed Function Call with a Parameter
func delayedFunctionWithParameter(timer : NSTimer) {
// check, wether a valid Object did come over
if let myUserInfo: AnyObject = timer.userInfo {
// alternatively, assuming it is a String for sure coming over
// if let myUserInfo: String = timer.userInfo as? String {
// assuming it is a string comming over
print("This is an advanced function beeing called with a parameter (in this case: \(myUserInfo)) passed")
}
timer.invalidate()
}
}
Notez que dans tous les cas, vous devez implémenter la fonction différée avec le paramètre (timer: NSTimer) pour pouvoir invalider (terminer, terminer) le timer. Et avec le "timer" de passe, vous avez également accès à userInfo (et vous pouvez y placer n'importe quel objet, pas seulement String-Objects, ainsi que des types de collection tels que des tableaux et des dictionnaires).
Les documentations d'origine Apple indiquent "" -> Le temporisateur se passe lui-même comme argument. La méthode adoptera donc le modèle suivant: void) timerFireMethod: (NSTimer *) timer Lecture complète -> --- (ici
Comme ce fil de discussion m'a fait essayer de mettre le minuteur sur un RunLoop moi-même (ce qui a résolu mon problème), je poste aussi mon cas spécifique - qui sait peut-être que cela peut aider quelqu'un. Mon minuteur est créé lors du démarrage de l'application et de l'initialisation de tous les objets. Mon problème était que, bien qu'il ait programmé le chronomètre, il ne s'est toujours pas déclenché. J'imagine que c'était le cas parce que scheduledTimerWithTimeInterval
plaçait le minuteur sur un autre RunLoop lors du démarrage de l'application. Si je viens d'initialiser le chronomètre et d'utiliser ensuite NSRunLoop.mainRunLoop().addTimer(myTimer, forMode:NSDefaultRunLoopMode)
, cela fonctionne correctement.
Avec Swift3, vous pouvez le lancer avec,
var timer: Timer?
func startTimer() {
if timer == nil {
timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(self.loop), userInfo: nil, repeats: true)
}
}
func stopTimer() {
if timer != nil {
timer?.invalidate()
timer = nil
}
}
func loop() {
//do something
}
Pour le faire avec la méthode suggérée par l'OP, vous devez l'ajouter à une boucle d'exécution:
myTimer = NSTimer(timeInterval: 5.0, target: self, selector:"timerFunc", userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(myTimer, forMode:NSDefaultRunLoopMode)
La documentation indique également que la cible doit accepter un argument, mais que cela ne fonctionne pas.
func timerFireMethod(timer: NSTimer) { }