2014-09-20 37 views
71

Come posso eseguire una funzione ogni minuto? In JavaScript posso fare qualcosa come setInterval, esiste qualcosa di simile in Swift?Fai qualcosa ogni x minuti in Swift

uscita Ricercato:

Ciao Mondo una volta al minuto ...

+0

aggiornato per Swift 2: [Swift Timer] (http://www.ios-blog.co.uk/tutorials/swift/swift-nstimer-tutorial-lets-create-a-counter-application/) – JamesG

+0

Come posso farlo nell'obiettivo C? –

risposta

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

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

Ricordarsi di importare 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

ma cosa succede se si desidera passare da una vista all'altra? Il codice si fermerà giusto? – Cing

+5

@Cing dipende da cosa si riferisce a se stesso. – Antzi

+1

Non dimenticare che 'NSTimer' mantiene il suo obiettivo, quindi, con questa configurazione, se' helloWorldTimer' è una proprietà su 'self' hai un ciclo di conservazione, dove' self' mantiene 'helloWorldTimer' e' helloWorldTimer 'conserva 'sé'. –

10

È possibile utilizzare NSTimer

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

Nel selettore() si mette in nome della funzione

+0

Come puoi farlo in swift 3? – bibscy

103

In Swift 3, è possibile creare un Timer. E se il targeting iOS versione 10 e versioni successive, è possibile utilizzare la resa basata su blocchi, che semplifica i potenziali cicli di riferimento forti, ad es .:

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() 
} 

In Swift 2, si crea un NSTimer. E se si sta utilizzando Swift 2, si può ben essere utilizzando la versione di iOS prima di 10.0, nel qual caso si deve utilizzare il più vecchio target/selector modello:

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() 
} 

Mentre NSTimer è generalmente migliore, per completezza, devo notare che è possibile utilizzare anche il timer di invio, utile per pianificare i timer sui thread in background. Con i timer di invio, dal momento che sono basati su blocchi, evita alcune delle forti sfide del ciclo di riferimento con il vecchio modello-/selector di NSTimer, purché si utilizzino i riferimenti weak.

Così, a 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() 
} 

In 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() 
} 

Per ulteriori informazioni, vedere la la Creazione di una sezione timer degli esempi Fonte dispatch nel Dispatch Sources sezione della Guida alla programmazione simultanea .

+0

come andrebbe per un timer execute-only-once all'interno di questo approccio? –

+0

@JuanPabloBoero - Non userei questo approccio per situazioni di incendio una volta. Dovresti usare "dispatch_after". Oppure un 'NSTimer' non ripetuto. – Rob

+0

@Rob Ho un'etichetta contatore sullo schermo che viene aggiornata ogni secondo da una funzione, e sto usando il codice sopra per incrementare il mio contatore e aggiornare il testo dell'etichetta. Ma il problema che sto affrontando è che la mia variabile contatore viene aggiornata ogni secondo, ma lo schermo non mostra l'ultimo valore del contatore nella mia UILabel. – Rao

5

a Swift 3.0 GCD ha fatto riscritta:

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

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

Questo è particolarmente utile per quando si ha bisogno di inviare su un particolare della coda. Inoltre, se hai intenzione di utilizzarlo per l'aggiornamento dell'interfaccia utente, ti suggerisco di esaminare CADisplayLink perché è sincronizzato con la frequenza di aggiornamento della GPU.

11

Ecco un aggiornamento per il NSTimer risposta, per Swift 3 (in cui NSTimer stato rinominato in Timer) utilizzando una chiusura piuttosto che una funzione denominata:

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

solo per iOS 10. – Glenn

+0

per favore non pubblicare soluzioni ios 10+ –

0

Se si può consentire un certo tempo di deriva ecco una soluzione semplice l'esecuzione di codice ogni minuto:

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

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

solo correre executeRepeatedly() una sola volta e sarà eseguito ogni minuto. L'esecuzione si interrompe quando viene rilasciato l'oggetto proprietario (self). Puoi anche usare una bandiera per indicare che l'esecuzione deve cessare.

Problemi correlati