Bagaimana saya bisa menggunakan Timer (sebelumnya NSTimer) di Swift?

257

Saya mencoba

var timer = NSTimer()
timer(timeInterval: 0.01, target: self, selector: update, userInfo: nil, repeats: false)

Tapi, saya mendapat pesan kesalahan

'(timeInterval: $T1, target: ViewController, selector: () -> (), userInfo: NilType, repeats: Bool) -> $T6' is not identical to 'NSTimer'
pengguna3225917
sumber
1
"Bagaimana saya bisa menggunakan NSTimer di Swift?" - cara yang sama Anda menggunakannya di Objective-C. API-nya tidak berubah.
The Paramagnetic Croissant

Jawaban:

535

Ini akan berhasil:

override func viewDidLoad() {
    super.viewDidLoad()
    // Swift block syntax (iOS 10+)
    let timer = Timer(timeInterval: 0.4, repeats: true) { _ in print("Done!") }
    // Swift >=3 selector syntax
    let timer = Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
    // Swift 2.2 selector syntax
    let timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: #selector(MyClass.update), userInfo: nil, repeats: true)
    // Swift <2.2 selector syntax
    let timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: "update", userInfo: nil, repeats: true)
}

// must be internal or public. 
@objc func update() {
    // Something cool
}

Untuk Swift 4, metode yang Anda inginkan untuk mendapatkan pemilih harus diekspos ke Objective-C, sehingga @objcatribut harus ditambahkan ke deklarasi metode.

Oscar Swanros
sumber
2
Saya akan menambahkan bahwa kelas dengan metode ini harus berupa NSObject, jika tidak Anda akan menemukan kesalahan pemilih yang tidak dikenal
Joshua
27
Pada Xcode 6.1, saya harus menambahkan "@objc" ke header fungsi seperti ini: "@objc func pembaruan () {". Tanpanya aplikasi crash pada kebakaran pertama.
kev
Anda dapat mendeklarasikan timer Var: NSTimer! awalnya dan gunakan kapanpun dibutuhkan!
Nigilan
1
Versi yang mungkin lebih berguna dari sintaks blok: let timer = Timer.scheduledTimer (withTimeInterval: timeout, repeate: false) {_ in print ("Done.")}
Teo Sartori
Anda tidak dapat menggunakan 'let timer = Timer (timeInterval: 0.4, repeats: true) {_ in print ("Done!")}' Ini tidak akan memulai timer dan kemudian Anda tidak bisa mengulanginya. Anda harus menggunakan Timer.scheduledTimer.
Siamaster
149

Acara berulang

Anda dapat menggunakan timer untuk melakukan suatu tindakan beberapa kali, seperti terlihat pada contoh berikut. Penghitung waktu memanggil metode untuk memperbarui label setiap setengah detik.

masukkan deskripsi gambar di sini

Ini kode untuk itu:

import UIKit

class ViewController: UIViewController {

    var counter = 0
    var timer = Timer()

    @IBOutlet weak var label: UILabel!

    // start timer
    @IBAction func startTimerButtonTapped(sender: UIButton) {
        timer.invalidate() // just in case this button is tapped multiple times

        // start the timer
        timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
    }

    // stop timer
    @IBAction func cancelTimerButtonTapped(sender: UIButton) {
        timer.invalidate()
    }

    // called every time interval from the timer
    func timerAction() {
        counter += 1
        label.text = "\(counter)"
    }
}

Acara yang tertunda

Anda juga dapat menggunakan timer untuk menjadwalkan acara satu kali untuk beberapa waktu di masa mendatang. Perbedaan utama dari contoh di atas adalah bahwa Anda menggunakan repeats: falsebukan true.

timer = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)

Contoh di atas memanggil metode yang dinamai delayedActiondua detik setelah timer disetel. Itu tidak diulang, tetapi Anda masih bisa menelepon timer.invalidate()jika Anda harus membatalkan acara sebelum itu terjadi.

Catatan

  • Jika ada kemungkinan memulai instance timer Anda beberapa kali, pastikan Anda membatalkan instance timer lama terlebih dahulu. Kalau tidak, Anda kehilangan referensi ke timer dan Anda tidak bisa menghentikannya lagi. (lihat T&J ini )
  • Jangan gunakan timer ketika itu tidak dibutuhkan. Lihat bagian pengatur waktu dari Panduan Efisiensi Energi untuk Aplikasi iOS .

Terkait

Suragch
sumber
1
@raddevus, terima kasih telah memberi tahu saya. Saya menghapus komentar Swift 3 yang lama.
Suragch
31

Diperbarui ke Swift 4, meningkatkan userInfo:

class TimerSample {

    var timer: Timer?

    func startTimer() {
        timer = Timer.scheduledTimer(timeInterval: 5.0,
                                     target: self,
                                     selector: #selector(eventWith(timer:)),
                                     userInfo: [ "foo" : "bar" ],
                                     repeats: true)
    }

    // Timer expects @objc selector
    @objc func eventWith(timer: Timer!) {
        let info = timer.userInfo as Any
        print(info)
    }

}
igraczech
sumber
2
Perlihatkan contoh yang berfungsi, apa artinya "kustom" dan "data" jika fungsi mengharapkan NSTimerobjek
Carlos.V
1
Itu benar-benar tidak masalah. Anda bebas menyimpan apa pun yang Anda butuhkan ke dalam kamus userInfo, dalam hal ini pasangan kunci-nilai sewenang-wenang.
igraczech
Ini berguna, tetapi gagal di Swift 3, contoh kerja: Timer.scheduledTimer (timeInterval: 1.0, target: self, selector: #selector (event), userInfo: "Info Terkirim", pengulangan: true)
Bobby
28

Pada iOS 10 ada juga metode Timer pabrik berbasis blok baru yang lebih bersih daripada menggunakan pemilih:

    _ = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { timer in
        label.isHidden = true
    }
Josh Homann
sumber
1
Cara Anda melakukannya, bukankah lebih baik menghapus _ = saja dan mulai saja Timer?
Sayang
2
Anda dapat menghilangkan _ = jika Anda membungkam peringatan tentang nilai yang tidak digunakan atau jika Anda tidak peduli dengan peringatan. Saya tidak suka memeriksa kode dengan peringatan.
Josh Homann
22

Swift 3, sebelum iOS 10

func schedule() {
    DispatchQueue.main.async {
      self.timer = Timer.scheduledTimer(timeInterval: 20, target: self,
                                   selector: #selector(self.timerDidFire(timer:)), userInfo: nil, repeats: false)
    }
  }

  @objc private func timerDidFire(timer: Timer) {
    print(timer)
  }

Swift 3, iOS 10+

DispatchQueue.main.async {
      self.timer = Timer.scheduledTimer(withTimeInterval: 20, repeats: false) { timer in
        print(timer)
      }
    }

Catatan

  • Itu harus di antrian utama
  • Fungsi panggilan balik dapat menjadi publik, pribadi, ...
  • Fungsi panggilan balik harus @objc
onmyway133
sumber
1
Pemahaman saya adalah bahwa hanya callback timer yang harus berada di antrian utama dan yang berikut ini akan sedikit lebih efisien: self.timer = Timer.scheduledTimer (withTimeInterval: 20, berulang: false) {timer di DispatchQueue.main.async {print (timer)}}
Mathieu Frenette
Timer saya tidak memicu dari salah satu Objek saya dan itu membuat trik :)
Reimond Hill
@RondondHill Anda harus mengubahtimeInterval
onmyway133
17

Periksa dengan:

Cepat 2

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

Swift 3, 4, 5

var timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
Midhun MP
sumber
2
Saya sudah mencobanya tetapi dikatakan 'Tidak dapat menemukan kelebihan untuk' init 'yang menerima argumen yang disediakan'
user3225917
1
Sama di sini, saya mendapat kesalahan 'Tidak dapat menemukan kelebihan untuk' init 'yang menerima argumen yang disediakan'. Apakah garis ini benar-benar berfungsi?
Yangshun Tay
Saya mendapatkan kesalahan yang sama dengan @ yangshun. Apa jenis objeknya self? UIView ok?
SimplGy
@SimpleAsCouldBe: ya itu tidak apa
Midhun MP
func numberSubmitSuccess () {self.view.hideToastActivity () self.view.makeToast (pesan: "Jumlah yang Berhasil Didaftarkan") var timer = NSTimer.scheduledTimerWithTimeInterval (0,5, target: self, selector: "moveToBidderPage", user: info, n ulangi: false)} func moveToBidderPage () {biarkan loginPageView = self.storyboard? .instantiateViewControllerWithIdentifier ("bidderpageID") as! BidderPage self.navigationController? .PushViewController (loginPageView, animasi: true)}
AG
11

Anda harus menggunakan Timer alih-alih NSTimer di Swift 3.

Berikut ini sebuah contoh:

Timer.scheduledTimer(timeInterval: 1, 
    target: self, 
    selector: #selector(YourController.update), 
    userInfo: nil, 
    repeats: true)

// @objc selector expected for Timer
@objc func update() {
    // do what should happen when timer triggers an event
}
Ondrej Kvasnovsky
sumber
11

Cepat 5

Saya pribadi lebih suka Timer dengan penutupan blok:

    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (_) in
       // TODO: - whatever you want
    }
Wissa
sumber
Ketahuilah, ini hanya tersedia di macOS 10.12 atau lebih baru. Tidak yakin tentang ios.
jeff-h
Ini juga tersedia di iOS.
Wissa
7

untuk swift 3 dan Xcode 8.2 (senang memiliki blok, tetapi jika Anda mengkompilasi untuk iOS9 DAN ingin userInfo):

...

        self.timer = Timer(fireAt: fire,
                           interval: deltaT,
                           target: self,
                           selector: #selector(timerCallBack(timer:)),
                           userInfo: ["custom":"data"],
                           repeats: true)

        RunLoop.main.add(self.timer!, forMode: RunLoopMode.commonModes)
        self.timer!.fire()
}

func timerCallBack(timer: Timer!){
        let info = timer.userInfo
        print(info)
    }
ingconti
sumber
6

SimpleTimer (Swift 3.1)

Mengapa?

Ini adalah kelas pengatur waktu sederhana yang memungkinkan Anda untuk:

  • Pengatur waktu pencakupan lokal
  • Rantai
  • Satu garis
  • Gunakan panggilan balik reguler

Pemakaian:

SimpleTimer(interval: 3,repeats: true){print("tick")}.start()//Ticks every 3 secs

Kode:

class SimpleTimer {/*<--was named Timer, but since swift 3, NSTimer is now Timer*/
    typealias Tick = ()->Void
    var timer:Timer?
    var interval:TimeInterval /*in seconds*/
    var repeats:Bool
    var tick:Tick

    init( interval:TimeInterval, repeats:Bool = false, onTick:@escaping Tick){
        self.interval = interval
        self.repeats = repeats
        self.tick = onTick
    }
    func start(){
        timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(update), userInfo: nil, repeats: true)//swift 3 upgrade
    }
    func stop(){
        if(timer != nil){timer!.invalidate()}
    }
    /**
     * This method must be in the public or scope
     */
    @objc func update() {
        tick()
    }
}
eonist
sumber
Bagaimana cara menghentikan timer di dalam blok itu pada beberapa kondisi?
Pengembang Seluler iOS Android
Cukup simpan referensi ke timer di kelas lalu panggil saja stop. Kompilator xcode akan memberi tahu Anda apakah perlu melarikan diri dll.
eonist
3
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)

Dan Ciptakan Kesenangan Dengan Nama createEnemy

fund createEnemy ()
{
do anything ////
}
Khaled Hamdy
sumber
3

Pertama, nyatakan timer Anda

var timer: Timer?

Kemudian tambahkan baris di viewDidLoad () atau dalam fungsi apa pun yang Anda inginkan untuk memulai timer

timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(action), userInfo: nil, repeats: false)

Ini adalah fungsi yang Anda akan panggil balik untuk melakukan sesuatu yang pasti @objc

@objc func action () {
print("done")
}
jenius
sumber
2

Dalam Swift 3 sesuatu seperti ini dengan @objc:

func startTimerForResendingCode() {
    let timerIntervalForResendingCode = TimeInterval(60)
    Timer.scheduledTimer(timeInterval: timerIntervalForResendingCode,
                         target: self,
                         selector: #selector(timerEndedUp),
                         userInfo: nil,
                         repeats: false)
}




@objc func timerEndedUp() {
    output?.timerHasFinishedAndCodeMayBeResended()
}
Nik Kov
sumber
1

Jika Anda init metode timer

let timer = Timer(timeInterval: 3, target: self, selector: #selector(update(_:)), userInfo: [key : value], repeats: false)

func update(_ timer : Timer) {

}

kemudian tambahkan ke loop menggunakan metode pemilih lain tidak akan dipanggil

RunLoop.main.add(timer!, forMode: .defaultRunLoopMode)

CATATAN: Jika Anda ingin ini mengulangi membuat pengulangan benar dan menjaga referensi timer jika tidak metode pembaruan tidak akan dipanggil.

Jika Anda menggunakan metode ini.

Timer.scheduledTimer(timeInterval: seconds, target: self, selector: #selector(update(_:)), userInfo: nil, repeats: true)

simpan referensi untuk digunakan nanti jika pengulangan benar.

Surjeet Rajput
sumber
0

Saya mencoba melakukannya di Kelas NSObject dan ini berhasil bagi saya:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {  
print("Bang!") }
Álvaro Agüero
sumber
-2

NSTimer telah diubah namanya menjadi Timer di Swift 4.2. sintaks ini akan bekerja di 4.2:

let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(UIMenuController.update), userInfo: nil, repeats: true)
Reuni Jamtrax
sumber
Pengubahan nama terjadi di Swift 3 dan jawaban lain sudah melakukan pembaruan ...
Eric Aya