2016-11-15 76 views
6

Chcę wywołać metodę func adjustmentBestSongBpmHeartRate() co 1,1 sekundy. Użyłem Timera, ale to nie działa. Przeczytałem dokument i znalazłem wiele przykładowego kodu, nadal działa! Czy jest coś, co przeoczyłem?Timer.scheduledTimer nie działa w Swift 3

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

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

Nie sądzę, że musisz wywołać fire() –

+0

Zmieniłem 'repeatates: false' na' repeatats: true', to nadal nie działa. –

+0

Skąd to nazywasz? –

Odpowiedz

17

Metody zegarowe z selektorem mają mieć jeden parametr: sam czasomierz. Tak więc kod powinien naprawdę wyglądać następująco:

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

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

pamiętać, że jeśli aplikacja działa tylko na iOS> = 10, można użyć nowej metody, która przyjmuje blok powołać zamiast docelowej/selektora . Znacznie czystsze i bardziej typu bezpieczne:

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

Ten kod wyglądałby następująco:

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

Zauważ, że jeśli blok czasowy/zamknięcie potrzebuje dostępu do zmiennych instancji z klasy trzeba wziąć specjalny opiekę z self. Oto dobry wzór dla tego rodzaju kodu:

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 
    } 

Edit:

: Dodam, że sposób korzystania z selektora musi użyć Objective-C dynamiczne wysyłki. Możesz zadeklarować metodę z kwalifikatorem @objc, możesz zadeklarować całą klasę, która definiuje selektor z kwalifikatorem @objc, lub możesz uczynić klasę, która definiuje selektor podklasę NSObject lub dowolną klasę dziedziczącą po NSOBject. (Jest to dość powszechne, aby zdefiniować metodę timer wywołuje wewnątrz UIViewController, która jest podklasą NSObject, więc to „po prostu działa”.

2

I rozwiązali pytanie zadane przez siebie. Używam jabłkowego zegarek kontrolować aplikację. próbuję nacisnąć przycisk na apple Obserwować zaprezentować nową viewcontroller na iPhone.

Kiedy piszę timera w override func viewDidLoad(), timer nie działa. I przenieść timer override func viewWillAppear() to działa.

Myślę, że być może coś jest nie tak z kontrolowaniem przez zegarek Apple


+4

Jest to związane z przypisaniem pętli wątku. Możesz to zrobić ręcznie, dodając timer do pętli przetwarzania (na przykład: https://www.hackingwithswift.com/example-code/system/how-to-run-code-at-a-specific-time). W moim przypadku użyłem wysyłki w głównej kolejce i zaczęło działać. Dziwna rzecz: – Alfishe

+1

To samo przydarzyło mi się - unieważniłem timer w viewDidDisappear, ale ustawiłem go w viewDidLoad, więc za drugim razem, gdy widok zostanie wyświetlony, timer nie zaczął się – Nathan

10

Swift 3

W moim przypadku to działało po dodaniu do mojego sposobu prefiks @obj

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 
    } 
} 
+0

Dobra racja. Metoda wywoływana przez timer musi korzystać z przesyłania komunikatów typu Objective-C. –

+0

A co, jeśli twoja funkcja 'handleMyFunction' ma zakończenie takie jak:' completion: @escaping (String) -> (Void) '? To rzuca mi błąd. –

+0

@TomSpee, nie możesz tego zrobić. Timery mogą mieć tylko nie parametry lub pojedynczy parametr, którym jest sam zegar. Możesz być w stanie przekazać obsługę zakończenia do userInfo przez timer, przesyłając ją do typu 'id', ale nie jestem pewien. –

-1

Swift3

var timer = Timer() 

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

moje dwa centów. Przeczytałem o "didLoad" i podczas jego wywoływania. więc możemy korzystać z opóźnieniem:

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) 

    } 
2

Spróbuj tego -

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

Głównie problem musi być ze względu na iOS wersji mobile.