webentwicklung-frage-antwort-db.com.de

Timer.scheduledTimer funktioniert nicht in Swift 3

Ich möchte die Methode func adjustmentBestSongBpmHeartRate() alle 1,1 Sekunden aufrufen. Ich habe Timer benutzt, aber es funktioniert nicht. Ich habe das Dokument gelesen und eine Menge Beispielcode gefunden, es funktioniert immer noch! Gibt es etwas, was ich vermisst habe?

 timer = Timer.scheduledTimer(timeInterval: 1.1, target: self, selector: #selector(self.adjustmentBestSongBpmHeartRate), userInfo: nil, repeats: false)
 timer.fire()

 func adjustmentBestSongBpmHeartRate() {
    print("frr")
 }
12
Jing Bian

Timer-Methoden mit einem Selektor sollen einen Parameter haben: den Timer selbst. So sollte Ihr Code wirklich so aussehen: 1

Timer.scheduledTimer(timeInterval: 1.1, 
    target: self, 
    selector: #selector(self.adjustmentBestSongBpmHeartRate(_:), 
    userInfo: nil, 
    repeats: false)

@objc func adjustmentBestSongBpmHeartRate(_ timer: Timer) {
    print("frr")
 }

Wenn Ihre App nur unter iOS> = 10 ausgeführt wird, können Sie die neue Methode verwenden, für die ein Block anstelle eines Ziels/Selektors aufgerufen werden muss. Viel sauberer und typsicher:

class func scheduledTimer(withTimeInterval interval: TimeInterval, 
    repeats: Bool, 
    block: @escaping (Timer) -> Void) -> Timer

Dieser Code würde so aussehen:

 timer = Timer.scheduledTimer(withTimeInterval: 1.1, 
        repeats: false) {
    timer in
    //Put the code that be called by the timer here.
    print("frr")
    }

Wenn Ihr Zeitgeberblockabschluss Zugriff auf Instanzvariablen Ihrer Klasse benötigt, müssen Sie besonders auf self achten. Hier ist ein gutes Muster für diese Art von Code:

 timer = Timer.scheduledTimer(withTimeInterval: 1.1, 
        repeats: false) {

    //"[weak self]" creates a "capture group" for timer
    [weak self] timer in

    //Add a guard statement to bail out of the timer code 
    //if the object has been freed.
    guard let strongSelf = self else {
        return
    }
    //Put the code that be called by the timer here.
    print(strongSelf.someProperty)
    strongSelf.someOtherProperty = someValue
    }

Bearbeiten:

1: Ich sollte hinzufügen, dass die Methode, die Sie im Selektor verwenden, den dynamischen Dispatch von Objective-C verwenden muss. Sie können die Methode mit dem Qualifikationsmerkmal @objc deklarieren, die gesamte Klasse, die den Selektor definiert, mit dem Qualifikationsmerkmal @objc deklarieren, oder Sie können die Klasse, die den Selektor definiert, als Unterklasse von NSObject oder einer beliebigen Klasse, die von NSOBject erbt, festlegen. (Es ist durchaus üblich, die Methode zu definieren, die der Timer in einer UIViewController aufruft, einer Unterklasse von NSObject, damit es "einfach funktioniert").

/ - _ edit _

In Swift 4 müssen nun Methoden, die von Objective-C aufgerufen werden müssen, einzeln mit dem @objc-Qualifier gekennzeichnet werden. Der Kommentar "Es funktioniert einfach" stimmt nicht mehr.

20
Duncan C

Ich habe festgestellt, dass das Erstellen des Timers in einer OperationQueue-Operation nicht funktioniert hat. Ich gehe davon aus, dass es keinen Runloop gibt.

Daher hat der folgende Code mein Problem behoben:

   DispatchQueue.main.async {
            // timer needs a runloop?
            self.timeoutTimer = Timer.scheduledTimer(timeInterval: self.timeout, target: self, selector: #selector(self.onTimeout(_:)), userInfo: nil, repeats: false)
}
11
Nick H247

Swift 3

In meinem Fall hat es funktioniert, nachdem ich meiner Methode das Präfix @obj hinzugefügt habe

Class TestClass {
   private var timer: Timer?

   func start() {
        guard timer == nil else { return }
        timer = Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(handleMyFunction), userInfo: nil, repeats: false)
    }

    func stop() {
        guard timer != nil else { return }
        timer?.invalidate()
        timer = nil
    }


    @objc func handleMyFunction() {
        // Code here
    }
}
10
Jorge Casariego

Versuche dies - 

if #available(iOS 10.0, *) {
     self.timer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false, block: { _ in
         self.update()
     })
} else {
     self.timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(self.update), userInfo: nil, repeats: false)
}

Meistens liegt das Problem an der iOS-Version von Mobile.

4
Nikhil Manapure

Ich habe die von mir gestellte Frage gelöst ... Ich benutze Apple Watch, um meine iPhone-App zu steuern. Ich versuche, eine Taste auf der Apple Watch zu drücken, um einen neuen Viewcontroller auf dem iPhone zu präsentieren.

Wenn ich Timer in override func viewDidLoad() schreibe, funktioniert Timer nicht. Ich verschiebe Timer zu override func viewWillAppear() es funktioniert.

Ich denke, vielleicht stimmt etwas nicht mit der Kontrolle von Apple Watch


2
Jing Bian

Wenn Sie versuchen, den Timer direkt auf Klassenebene zu initialisieren, funktioniert dies nicht, wenn Sie einen Selektor in derselben Klasse anvisieren. Wenn es feuert, kann es den Wähler nicht finden.

Um dies zu umgehen, initialisiere ich nur den Timer, nachdemdas Objekt mit dem Selektor initialisiert wurde. Wenn es sich in derselben Klasse befindet, geben Sie den Initialisierungscode in die Variable ViewDidLoad oder eine ähnliche ein. Nur nicht im Initialisierer. Dann wird es klappen. Keine Versandwarteschlange erforderlich.

Not muss auch einen Selektor verwenden, der den Timer als Parameter akzeptiert. Sie können, aber im Gegensatz zu der Antwort mit einer Tonne Stimmen, stimmt das eigentlich nicht, oder genauer gesagt, es funktioniert gut für mich ohne es, genauso wie Sie es ohne es haben.

Ich denke übrigens, der Grund für das Funktionieren der Versandwarteschlange ist, dass Sie den Timer zwingen, nach der Initialisierung des Objekts erstellt zu werden, wodurch meine obige Anweisung bestätigt wird.

let timer:Timer?

override func viewDidLoad(){
    super.viewDidLoad()

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

    timer.fire()

}

func adjustmentBestSongBpmHeartRate() {
    print("frr")
}

Hinweis: Hierbei handelt es sich um Code aus dem Speicher, der nicht aus Xcode kopiert wurde, sodass er möglicherweise nicht kompiliert wird, aber hoffentlich haben Sie die Idee.

1
MarqueIV

Swift 5, Swift 4 Einfacher Anruf nur mit Dispatch Queue Async

DispatchQueue.main.async 
{
   self.andicator.stopAnimating()
   self.bgv.isHidden = true

   Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false, block: { _ in

       obj.showAlert(title: "Successfully!", message: "Video save successfully to Library directory.", viewController: self)

   })
}
1
Shakeel Ahmed

meine zwei Cents . Ich habe über "didLoad" gelesen und beim Aufruf . Wir können also eine Verzögerung verwenden:

class ViewController: UIViewController {

    var timer: Timer?

    override func viewDidLoad() {
        super.viewDidLoad()
        startTimer()
    }


    final func killTimer(){
        self.timer?.invalidate()
        self.timer = nil
    }


    final private func startTimer() {

        // make it re-entrant:
        // if timer is running, kill it and start from scratch
        self.killTimer()
        let fire = Date().addingTimeInterval(1)
        let deltaT : TimeInterval = 1.0

        self.timer = Timer(fire: fire, interval: deltaT, repeats: true, block: { (t: Timer) in

            print("hello")

        })

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

    }
0
ingconti

Swift

var timer = Timer()

timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.compruebaConexion), userInfo: nil, repeats: true)
0
user3711263