2014-09-20 4 views
71

Comment puis-je exécuter une fonction toutes les minutes? En JavaScript, je peux faire quelque chose comme setInterval, est-ce que quelque chose de similaire existe dans Swift?Faire quelque chose toutes les x minutes dans Swift

sortie Recherché:

Bonjour tout le monde une fois par minute ...

+0

Mis à jour pour Swift 2: [Minuteur rapide] (http://www.ios-blog.co.uk/tutorials/swift/swift-nstimer-tutorial-lets-create-a-counter-application/) – JamesG

+0

Comment puis-je faire cela dans l'objectif C? –

Répondre

120
var helloWorldTimer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: Selector("sayHello"), userInfo: nil, repeats: true) 

func sayHello() 
{ 
    NSLog("hello World") 
} 

N'oubliez pas d'importer Foundation.

Swift 3:

var helloWorldTimer = Timer.scheduledTimer(timeInterval: 60.0, target: self, selector: #selector(ViewController.sayHello), userInfo: nil, repeats: true) 

func sayHello() 
{ 
    NSLog("hello World") 
} 
+1

mais que faire si vous voulez passer d'une vue à l'autre? Le code va s'arrêter à droite? – Cing

+5

@Cing dépend de ce que l'on se réfère à. – Antzi

+1

N'oubliez pas que 'NSTimer' conserve sa cible, donc, avec cette configuration, si' helloWorldTimer' est une propriété sur 'self' vous avez vous-même un cycle de retenue, où' self' conserve 'helloWorldTimer' et' helloWorldTimer 'retient' self'. –

10

Vous pouvez utiliser NSTimer

var timer = NSTimer.scheduledTimerWithTimeInterval(60, target: self, selector: Selector("function"), userInfo: nil, repeats: true) 

Dans le sélecteur() vous mettez dans votre nom de la fonction

+0

Comment pouvez-vous le faire dans 3 rapide? – bibscy

103

Swift 3, vous pouvez créer un Timer. Et si le ciblage iOS version 10 et plus, vous pouvez utiliser le rendu par blocs, ce qui simplifie les cycles fort potentiel de référence, par exemple .:

weak var timer: Timer? 

func startTimer() { 
    timer?.invalidate() // just in case you had existing `Timer`, `invalidate` it before we lose our reference to it 
    timer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { [weak self] _ in 
     // do something here 
    } 
} 

func stopTimer() { 
    timer?.invalidate() 
} 

// if appropriate, make sure to stop your timer in `deinit` 

deinit { 
    stopTimer() 
} 

Swift 2, vous créez un NSTimer. Et si vous utilisez Swift 2, vous pouvez bien utiliser la version iOS avant 10.0, dans ce cas, vous devez utiliser le modèle plus target/selector:

weak var timer: NSTimer? 

func startTimer() { 
    timer?.invalidate() // just in case you had existing `NSTimer`, `invalidate` it before we lose our reference to it 
    timer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: #selector(handleTimer(_:)), userInfo: nil, repeats: true) 
} 

func handleTimer(timer: NSTimer) { 
    // do something here 
} 

func stopTimer() { 
    timer?.invalidate() 
} 

// because this old target/selector approach will keep a strong reference 
// to the `target`, if you want the timer to stop when the view controller 
// is dismissed, you can't stop the timer in `deinit`, but rather have to 
// detect the dismissing of the view controller using other mechanisms. Commonly, 
// we used to detect the view disappearing, like below: 

override func viewDidDisappear(animated: Bool) { 
    super.viewDidDisappear(animated) 
    stopTimer() 
} 

Alors que NSTimer est généralement préférable, pour être complet, je devrais noter que vous pouvez également utiliser le timer d'envoi, ce qui est utile pour planifier les minuteurs sur les threads d'arrière-plan. Avec les temporisateurs d'envoi, puisqu'ils sont basés sur des blocs, il évite certains des problèmes de cycle de référence forts avec l'ancien modèle target/selector de NSTimer, tant que vous utilisez les références weak.

Ainsi, Swift 3:

var timer: DispatchSourceTimer? 

func startTimer() { 
    let queue = DispatchQueue(label: "com.domain.app.timer") // you can also use `DispatchQueue.main`, if you want 
    timer = DispatchSource.makeTimerSource(queue: queue) 
    timer!.scheduleRepeating(deadline: .now(), interval: .seconds(60)) 
    timer!.setEventHandler { [weak self] in 
     // do whatever you want here 
    } 
    timer!.resume() 
} 

func stopTimer() { 
    timer?.cancel() 
    timer = nil 
} 

deinit { 
    self.stopTimer() 
} 

Swift 2:

var timer: dispatch_source_t? 

func startTimer() { 
    let queue = dispatch_queue_create("com.domain.app.timer", nil) // again, you can use `dispatch_get_main_queue()` if you want to use the main queue 
    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue) 
    dispatch_source_set_timer(timer!, DISPATCH_TIME_NOW, 60 * NSEC_PER_SEC, 1 * NSEC_PER_SEC) // every 60 seconds, with leeway of 1 second 
    dispatch_source_set_event_handler(timer!) { [weak self] in 
     // do whatever you want here 
    } 
    dispatch_resume(timer!) 
} 

func stopTimer() { 
    if let timer = timer { 
     dispatch_source_cancel(timer) 
     self.timer = nil 
    } 
} 

deinit { 
    self.stopTimer() 
} 

Pour plus d'informations, voir l'section Création d'une minuterie de Dispatch Exemples Source dans le Dispatch Sources section du Guide de programmation simultanée .

+0

Comment iriez-vous pour une temporisation d'exécution unique dans cette approche? –

+0

@JuanPabloBoero - Je n'utiliserais pas cette approche pour une situation de feu unique. Vous utiliseriez 'dispatch_after'. Ou un 'NSTimer' non répétitif. – Rob

+0

@Rob J'ai une étiquette de compteur sur l'écran qui est mise à jour chaque seconde à partir d'une fonction, et j'utilise le code ci-dessus pour incrémenter mon compteur et mettre à jour le texte de l'étiquette. Mais, le problème auquel je fais face est que ma variable compteur est mise à jour chaque seconde, mais l'écran ne montre pas la dernière valeur de compteur dans mon UILabel. – Rao

5

Dans rapide 3.0 GCD mais j'ai remaniée avec:

let timer : DispatchSourceTimer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main) 

timer.scheduleRepeating(deadline: .now(), interval: .seconds(60)) 
timer.setEventHandler 
{ 
    NSLog("Hello World") 
} 
timer.resume() 

Ceci est particulièrement utile lorsque vous devez envoyer une file d'attente particulière. Aussi, si vous envisagez d'utiliser ceci pour la mise à jour de l'interface utilisateur, je suggère de regarder CADisplayLink car il est synchronisé avec le taux de rafraîchissement du GPU.

11

est ici une mise à jour NSTimer réponse, Swift 3 (dans lequel NSTimer a été rebaptisée à Timer) à l'aide d'une fermeture plutôt que d'une fonction nommée:

var timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { 
    (_) in 
    print("Hello world") 
} 
+5

c'est pour iOS 10 seulement. – Glenn

+0

s'il vous plaît ne pas poster des solutions ios 10+ –

0

Si vous pouvez permettre une certaine dérive de temps voici une solution simple exécutant un code à chaque minute:

private func executeRepeatedly() { 
    // put your code here 

    DispatchQueue.main.asyncAfter(deadline: .now() + 60.0) { [weak self] in 
     self?.executeRepeatedly() 
    } 
} 

il suffit de lancer executeRepeatedly() une fois et il sera exécuté à chaque minute. L'exécution s'arrête lorsque l'objet propriétaire (self) est libéré. Vous pouvez également utiliser un indicateur pour indiquer que l'exécution doit s'arrêter.

Questions connexes