【问题标题】:Timer.scheduledTimer does not work in Swift 3Timer.scheduledTimer 在 Swift 3 中不起作用
【发布时间】:2016-11-15 15:23:15
【问题描述】:

我想每隔 1.1 秒调用一次方法 func adjustmentBestSongBpmHeartRate()。我用了定时器,但它不起作用。我已经阅读了文档并找到了很多示例代码,它仍然可以工作!有什么我错过的吗?

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

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

【问题讨论】:

  • 我认为你不需要调用 fire()
  • 我把repeats: false改成了repeats: true,还是不行。
  • 你从哪里称呼它?
  • 我也删了timer.fire(),没用....
  • 我从override func viewDidLoad()方法调用它

标签: ios swift swift3 timer


【解决方案1】:

我发现在 OperationQueue 操作中创建计时器不起作用。我认为这是因为没有运行循环。

因此,以下代码解决了我的问题:

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
    }

编辑(12 月 15 日更新)

1:我应该补充一点,您在选择器中使用的方法必须使用Objective-C动态调度。在 Swift 4 及更高版本中,您引用的各个方法必须使用 @objc 标记。在以前的 Swift 版本中,您还可以使用 @objc 限定符声明定义选择器的整个类,或者您可以使定义选择器的类成为 NSObject 或继承自 NSOBject 的任何类的子类。 (在UIViewController 中定义计时器调用的方法是很常见的,它是NSObject 的子类,因此它曾经“正常工作”。

【讨论】:

    【解决方案3】:

    斯威夫特 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
        }
    }
    

    【讨论】:

    • 好点。计时器调用的方法需要使用 Objective-C 消息传递。
    • 如果你的handleMyFunction 有一个像completion: @escaping (String) -> (Void) 这样的补全呢?这对我来说是一个错误。
    • @TomSpee,你不能那样做。定时器只能没有参数,或者只有一个参数,即定时器本身。您可以将完成处理程序作为 userInfo 传递给计时器,方法是将其转换为类型 id,但我不确定。
    【解决方案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】:

      Swift 5, Swift 4 简单的方法只调用 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)
      
         })
      }
      

      【讨论】:

        【解决方案6】:

        我已经解决了自己提出的问题。 我正在使用 Apple Watch 来控制我的 iPhone 应用程序。 我尝试按下 Apple Watch 上的按钮以在 iphone 上呈现新的视图控制器。

        当我在override func viewDidLoad() 中编写 Timer 时,Timer 不起作用。我将 Timer 移至 override func viewWillAppear() 它可以工作。

        我觉得用apple watch控制可能有问题


        【讨论】:

        • 跟线程的循环赋值有关。您可以通过手动将计时器添加到处理循环来管理它(例如:hackingwithswift.com/example-code/system/…)。就我而言,我在主队列中使用了调度,它开始工作。奇怪的事情
        • 同样的事情发生在我身上 - 我在 viewDidDisappear 中使计时器无效,但在 viewDidLoad 中设置它,所以第二次显示视图时,计时器没有启动
        【解决方案7】:

        我发现,如果您尝试直接在类级别初始化计时器,那么如果您针对的是同一类中的选择器,它将无法正常工作。当它触发时,它找不到选择器。

        为了解决这个问题,我只在包含选择器的对象被初始化之后才初始化计时器。如果是同一个类,把初始化代码放在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 复制的,因此它可能无法编译,但希望您能理解。

        【讨论】:

          【解决方案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)
            
                }
            

            【讨论】:

              猜你喜欢
              • 2016-12-06
              • 1970-01-01
              • 1970-01-01
              • 2017-02-07
              • 2018-01-13
              • 2017-09-12
              • 1970-01-01
              • 1970-01-01
              • 2017-03-22
              相关资源
              最近更新 更多