ฉันจะใช้ตัวจับเวลา (เดิมคือ NSTimer) ใน Swift ได้อย่างไร


257

ฉันเหนื่อย

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

แต่ฉันพบข้อผิดพลาด

'(timeInterval: $T1, target: ViewController, selector: () -> (), userInfo: NilType, repeats: Bool) -> $T6' is not identical to 'NSTimer'

1
"ฉันจะใช้ NSTimer ใน Swift ได้อย่างไร" - เช่นเดียวกับที่คุณใช้ใน Objective-C API ของมันไม่เปลี่ยนแปลง
ครัวซองต์ Paramagnetic

คำตอบ:


534

สิ่งนี้จะได้ผล:

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
}

สำหรับ Swift 4 วิธีการที่คุณต้องการให้ตัวเลือกต้องถูกเปิดเผยใน Objective-C ดังนั้นจึง@objcต้องเพิ่มแอตทริบิวต์ในการประกาศเมธอด


2
ฉันจะเพิ่มว่าชั้นเรียนด้วยวิธีการเหล่านี้จะต้องเป็น NSObject มิฉะนั้นคุณจะจบลงด้วยข้อผิดพลาดของตัวเลือกที่ไม่รู้จัก
Joshua

27
ในฐานะของ Xcode 6.1 ฉันต้องเพิ่ม "@objc" ลงในส่วนหัวของฟังก์ชั่นดังนี้: "@objc func update () {" แอพจะไม่ทำงานเมื่อเกิดไฟไหม้ครั้งแรก
kev

คุณสามารถประกาศตัวจับเวลา Var: NSTimer! เริ่มแรกและใช้เมื่อต้องการ!
Nigilan

1
เวอร์ชันที่มีประโยชน์มากกว่าของไวยากรณ์บล็อก: let timer = Timer.scheduledTimer (withTimeInterval: หมดเวลาซ้ำ: false) {_ ในการพิมพ์ ("เสร็จสิ้น")}
Teo Sartori

คุณไม่สามารถใช้ 'let timer = Timer (timeInterval: 0.4, repeats: true) {_ in print ("Done!")}' สิ่งนี้จะไม่เริ่มจับเวลาจากนั้นคุณจะไม่สามารถทำซ้ำได้ คุณต้องใช้ Timer.scheduledTimer
Siamaster

149

เหตุการณ์ที่เกิดซ้ำ

คุณสามารถใช้ตัวจับเวลาเพื่อดำเนินการหลาย ๆ ครั้งตามที่เห็นในตัวอย่างต่อไปนี้ ตัวจับเวลาเรียกวิธีการอัปเดตฉลากทุกครึ่งวินาที

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือรหัสสำหรับที่:

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

เหตุการณ์ล่าช้า

นอกจากนี้คุณยังสามารถใช้ตัวจับเวลาเพื่อกำหนดเวลาเหตุการณ์หนึ่งครั้งในอนาคต แตกต่างหลักจากตัวอย่างข้างต้นคือการที่คุณใช้แทนrepeats: falsetrue

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

ตัวอย่างด้านบนเรียกเมธอดชื่อdelayedActionสองวินาทีหลังจากตัวจับเวลาถูกตั้งค่า มันไม่ได้ทำซ้ำ แต่คุณยังสามารถโทรได้timer.invalidate()หากคุณต้องการยกเลิกกิจกรรมก่อนที่จะเกิดขึ้น

หมายเหตุ

  • หากมีโอกาสใด ๆ ที่จะเริ่มต้นอินสแตนซ์ตัวจับเวลาของคุณหลายครั้งตรวจสอบให้แน่ใจว่าคุณได้ทำให้อินสแตนซ์ตัวจับเวลาเก่าใช้ไม่ได้ก่อน มิฉะนั้นคุณจะสูญเสียการอ้างอิงถึงตัวจับเวลาและคุณไม่สามารถหยุดมันได้อีกต่อไป (ดูคำถาม & คำตอบนี้ )
  • อย่าใช้ตัวจับเวลาเมื่อไม่ต้องการใช้ ดูส่วนจับเวลาของคู่มือประสิทธิภาพการใช้พลังงานสำหรับ iOS ปพลิเคชัน

ที่เกี่ยวข้อง


1
@ raddevus ขอบคุณที่แจ้งให้เราทราบ ฉันลบความคิดเห็นเก่าของ Swift 3
Suragch

31

อัปเดตเป็น Swift 4 ใช้ประโยชน์จากผู้ใช้อินโฟ:

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

}

2
แสดงตัวอย่างการทำงาน "กำหนดเอง" และ "ข้อมูล" หมายถึงอะไรถ้าฟังก์ชันคาดหวังว่าNSTimerวัตถุ
Carlos.V

1
มันไม่สำคัญหรอก คุณสามารถเก็บทุกสิ่งที่คุณต้องการลงในพจนานุกรม userInfo ได้ในกรณีนี้มันคือคู่ของคีย์ - ค่าเอง
igraczech

สิ่งนี้มีประโยชน์ แต่ยากจนใน Swift 3 ตัวอย่างการทำงาน: Timer.scheduledTimer (timeInterval: 1.0, target: self, selector: #selector (event), userInfo: "ข้อมูลถูกส่ง", ทำซ้ำ: จริง)
Bobby

28

ในฐานะของ iOS 10 ยังมีวิธีการตั้งเวลาบล็อกตามโรงงานใหม่ซึ่งสะอาดกว่าการใช้ตัวเลือก:

    _ = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { timer in
        label.isHidden = true
    }

1
ในแบบที่คุณทำมันจะดีกว่าไหมถ้าจะลบ_ = และเริ่มต้นด้วยTimer?
น้ำผึ้ง

2
คุณสามารถละเว้น _ = ถ้าคุณปิดเสียงเตือนเกี่ยวกับค่าที่ไม่ได้ใช้หรือถ้าคุณไม่สนใจคำเตือน ฉันไม่ชอบที่จะตรวจสอบรหัสด้วยคำเตือน
Josh Homann

22

Swift 3 ก่อน 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)
      }
    }

หมายเหตุ

  • มันจะต้องอยู่ในคิวหลัก
  • ฟังก์ชันการโทรกลับสามารถเป็นสาธารณะส่วนตัว ...
  • ฟังก์ชั่นการโทรกลับต้องเป็น @objc

1
ความเข้าใจของฉันคือเฉพาะการโทรกลับจับเวลาควรอยู่ในคิวหลักและต่อไปนี้จะมีประสิทธิภาพมากขึ้นเล็กน้อย: self.timer = Timer.scheduledTimer (withTimeInterval: 20 ซ้ำ: เท็จ) {ตัวจับเวลาใน DispatchQueue.main.async {print (ตัวจับเวลา)}}
Mathieu Frenette

จับเวลาของฉันไม่ได้เรียกจากหนึ่งในวัตถุของฉันและที่ทำเคล็ดลับ :)
Reimond ฮิลล์

@ReimondHill คุณจำเป็นต้องเปลี่ยนtimeInterval
onmyway133

17

ตรวจสอบกับ:

สวิฟท์ 2

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

สวิฟท์ 3, 4, 5

var timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)

2
ฉันลองแล้ว แต่มันบอกว่า 'ไม่พบการโอเวอร์โหลดสำหรับ' init 'ที่ยอมรับการขัดแย้งที่ให้มา'
user3225917

1
เช่นเดียวกันที่นี่ฉันได้รับข้อผิดพลาด 'ไม่พบการโอเวอร์โหลดสำหรับ' init 'ที่ยอมรับอาร์กิวเมนต์ที่ให้มา' บรรทัดนี้ใช้งานได้จริงหรือ
Yangshun Tay

ฉันได้รับข้อผิดพลาดเดียวกับ @yangshun วัตถุประเภทใดต้องselfเป็น UIView ไม่เป็นไร
SimplGy

@SimpleAsCouldBe: ใช่ว่าไม่เป็นไร
Midhun MP

func amountSubmitSuccess () {self.view.hideToastActivity () self.view.makeToast (ข้อความ: "จำนวนที่ลงทะเบียนสำเร็จแล้ว") var timer = NSTimer.scheduledTimerWithTimeInterval (0.5 เป้าหมาย: ตนเองเลือก: "moveToBidderPage", userInfo: nil ทำซ้ำ: false)} func moveToBidderPage () {ให้ loginPageView = self.storyboard? .instantiateViewControllerWithIdentifier ("bidderpageID") เป็น! BidderPage self.navigationController? .pushViewController (loginPageView, ภาพเคลื่อนไหว: จริง)}
AG

11

คุณจะต้องใช้ตัวจับเวลาแทน NSTimer ใน Swift 3

นี่คือตัวอย่าง:

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
}

11

สวิฟท์ 5

ฉันชอบตัวจับเวลาด้วยการปิดบล็อก:

    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (_) in
       // TODO: - whatever you want
    }

โปรดทราบว่ามีเฉพาะใน macOS 10.12 หรือใหม่กว่าเท่านั้น ไม่แน่ใจเกี่ยวกับ iOS
jeff-h

มันมีอยู่ใน iOS ด้วยเช่นกัน
Wissa

7

สำหรับ swift 3 และ Xcode 8.2 (ดีที่มีบล็อก แต่ถ้าคุณคอมไพล์สำหรับ iOS9 และต้องการ 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)
    }

6

SimpleTimer (Swift 3.1)

ทำไม?

นี่คือคลาสตัวจับเวลาอย่างง่ายในสวิฟท์ที่ช่วยให้คุณ:

  • ตัวจับเวลาที่กำหนดขอบเขตท้องถิ่น
  • chainable
  • หนึ่งสมุทร
  • ใช้การโทรกลับปกติ

การใช้งาน:

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

รหัส:

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

วิธีหยุดตัวจับเวลาภายในบล็อกนั้นในบางเงื่อนไข
นักพัฒนามือถือ iOS Android

เพียงแค่เก็บการอ้างอิงถึงตัวจับเวลาในคลาสแล้วเพียงแค่โทรหยุด คอมไพเลอร์ Xcode จะบอกคุณว่ามันต้องหลบหนี ฯลฯ
eonist

3
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)

และสร้างความสนุกด้วยชื่อ createEnemy

fund createEnemy ()
{
do anything ////
}

3

ก่อนอื่นให้ประกาศตัวจับเวลาของคุณ

var timer: Timer?

จากนั้นเพิ่มบรรทัดใน viewDidLoad () หรือในฟังก์ชันใด ๆ ที่คุณต้องการเริ่มจับเวลา

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

นี่คือ func คุณจะโทรกลับเพื่อทำสิ่งที่มันต้องเป็น @objc

@objc func action () {
print("done")
}

2

ในSwift 3บางสิ่งเช่นนี้กับ @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()
}

1

หากคุณเริ่มวิธีจับเวลา

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

func update(_ timer : Timer) {

}

จากนั้นเพิ่มลงในลูปโดยใช้วิธีที่ตัวเลือกอื่นจะไม่ถูกเรียก

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

หมายเหตุ: หากคุณต้องการให้การทำซ้ำเป็นจริงและเก็บการอ้างอิงของตัวจับเวลามิฉะนั้นจะไม่เรียกวิธีการอัปเดต

หากคุณใช้วิธีนี้

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

เก็บข้อมูลอ้างอิงไว้เพื่อใช้ในภายหลังหากทำซ้ำเป็นความจริง


0

ฉันพยายามทำใน NSObject Class และสิ่งนี้ใช้ได้สำหรับฉัน:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {  
print("Bang!") }

-2

NSTimer ถูกเปลี่ยนชื่อเป็น Timer ใน Swift 4.2 ไวยากรณ์นี้จะทำงานใน 4.2:

let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(UIMenuController.update), userInfo: nil, repeats: true)

เปลี่ยนชื่อสวิฟท์ที่เกิดขึ้นใน3และคำตอบอื่น ๆ แล้วได้กระทำการปรับปรุง ...
เอริคอายะ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.