Timer.scheduledTimer在Swift 3中不起作用

时间:2016-11-15 15:23:15

标签: ios swift swift3 timer

我想每1.1秒调用一次方法func adjustmentBestSongBpmHeartRate()。我用过Timer,但它不起作用。我已阅读该文档并发现了大量示例代码,它仍然可以正常工作!我错过了什么吗?

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

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

8 个答案:

答案 0 :(得分:20)

带选择器的计时器方法应该有一个参数:计时器本身。因此,您的代码应该看起来像这样: 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
    }

编辑:

1 :我应该补充一点,你在选择器中使用的方法必须使用Objective-C动态调度。您可以使用@objc限定符声明方法,可以使用@objc限定符声明定义选择器的整个类,也可以使定义选择器的类成为{{1}的子类或者任何继承自NSObject的类。 (定义计时器在NSOBject内调用的方法是很常见的,UIViewControllerNSObject的子类,所以它“正常”。

修改

在Swift 4中,需要从Objective-C调用的方法现在需要使用@objc限定符单独标记。 “它只是有效”的评论不再适用。

答案 1 :(得分:15)

我发现在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 :(得分:10)

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

答案 3 :(得分: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版手机。

答案 4 :(得分:2)

我已经解决了自己提出的问题。 我使用苹果手表来控制我的iPhone应用程序。 我试着按下苹果手表上的一个按钮,在iphone上展示一个新的viewcontroller。

当我在override func viewDidLoad()中写入Timer时,Timer无法正常工作。我将Timer移动到override func viewWillAppear()它可以工作。

我认为苹果手表控制可能存在问题

答案 5 :(得分:1)

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

要解决此问题,我仅在包含选择器的对象已初始化后 初始化计时器。如果在同一类中,请将初始化代码放入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复制的,因此它可能无法编译,但希望您能理解。

答案 6 :(得分:0)

我的两分钱。 我读到了" 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)

    }

答案 7 :(得分:0)

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)

   })
}