Timer.scheduledTimer не работает в Swift 3
Я хочу вызвать метод func adjustmentBestSongBpmHeartRate()
каждые 1,1 секунды. Я использовал таймер, но он не работает. Я прочитал документ и нашел много примеров кода, он все еще работает! Я что-то пропустил?
timer = Timer.scheduledTimer(timeInterval: 1.1, target: self, selector: #selector(self.adjustmentBestSongBpmHeartRate), userInfo: nil, repeats: false)
timer.fire()
func adjustmentBestSongBpmHeartRate() {
print("frr")
}
Ответы
Ответ 1
Я обнаружил, что создание таймера в OperationQueue Operation не работает. Я предполагаю, что это потому, что нет runloop.
Поэтому следующий код решил мою проблему:
DispatchQueue.main.async {
// timer needs a runloop?
self.timeoutTimer = Timer.scheduledTimer(timeInterval: self.timeout, target: self, selector: #selector(self.onTimeout(_:)), userInfo: nil, repeats: false)
}
Ответ 2
Методы таймера с селектором должны иметь один параметр: сам таймер. Таким образом, ваш код должен выглядеть так: 1
Timer.scheduledTimer(timeInterval: 1.1,
target: self,
selector: #selector(self.adjustmentBestSongBpmHeartRate(_:),
userInfo: nil,
repeats: false)
@objc func adjustmentBestSongBpmHeartRate(_ timer: Timer) {
print("frr")
}
Обратите внимание, что если ваше приложение работает только на iOS> = 10, вы можете использовать новый метод, который использует для вызова блок, а не цель/селектор. Намного чище и безопаснее:
class func scheduledTimer(withTimeInterval interval: TimeInterval,
repeats: Bool,
block: @escaping (Timer) -> Void) -> Timer
Этот код будет выглядеть так:
timer = Timer.scheduledTimer(withTimeInterval: 1.1,
repeats: false) {
timer in
//Put the code that be called by the timer here.
print("frr")
}
Обратите внимание, что если вашему блоку таймера/закрытию требуется доступ к переменным экземпляра из вашего класса, вы должны быть особенно осторожны с self
. Вот хороший шаблон для такого рода кода:
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:
1: Я должен добавить, что метод, который вы используете в селекторе, должен использовать динамическую диспетчеризацию Objective-C. Вы можете объявить метод с помощью квалификатора @objc
, вы можете объявить весь класс, который определяет селектор, с помощью квалификатора @objc
, или вы можете сделать класс, который определяет селектор, подклассом NSObject
или любым классом, который наследует из NSOBject
. (Довольно часто определяют метод, который таймер вызывает внутри UIViewController
, который является подклассом NSObject
, поэтому он "просто работает".
EDIT
В Swift 4 методы, которые необходимо вызывать из Objective-C, теперь должны быть индивидуально помечены квалификатором @objc
. Комментарий "это просто работает" больше не соответствует действительности.
Ответ 3
Swift 3
В моем случае это сработало после того, как я добавил в свой метод префикс @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
}
}
Ответ 4
Попробуйте это -
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)
}
В основном проблема должна была быть из-за версии iOS для мобильных устройств.
Ответ 5
Я решил вопрос, заданный мной.
Я использую apple watch для управления своим приложением iphone.
Я пытаюсь нажать кнопку на яблочном часе, чтобы представить новый диспетчер представлений на iphone.
Когда я пишу таймер в override func viewDidLoad()
, таймер не работает. Я перемещаю Таймер на override func viewWillAppear()
, он работает.
Я думаю, может быть, что-то не так с контролем над яблочными часами
Ответ 6
Я обнаружил, что если вы попытаетесь инициализировать таймер непосредственно на уровне класса, он не будет работать, если вы нацелены на селектор в этом же классе. Когда он срабатывает, он не может найти селектор.
Чтобы обойти это, я инициализирую таймер только после того, как объект, содержащий селектор, был инициализирован. Если это в том же классе, поместите код инициализации в ViewDidLoad
или аналогичный. Просто нет в инициализаторе. Тогда это будет работать. Очередь отправки не требуется.
Кроме того, вам не нужно использовать селектор, который принимает таймер в качестве параметра. Вы можете, но вопреки ответу с тонной голосов, что на самом деле это не так, или, точнее говоря, он отлично работает для меня без него, так же, как у вас это без него.
Между прочим, я думаю, что причина, по которой сработала очередь отправки, заключается в том, что вы заставляете таймер создаваться после инициализации объекта, подтверждая мое приведенное выше утверждение.
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")
}
Примечание. Это код, набранный из памяти, а не скопированный из Xcode, поэтому он может не скомпилироваться, но, надеюсь, вы поняли идею.
Ответ 7
Swift 5, Swift 4 Простой способ вызова только с асинхронной очередью отправки
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)
})
}
Ответ 8
Swift3
var timer = Timer()
timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.compruebaConexion), userInfo: nil, repeats: true)
Ответ 9
мои два цента.
Я читал о "didLoad" и при вызове.
поэтому мы можем использовать задержку:
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)
}