在Swift上设置计时器 [英] Set Timer on Swift

查看:553
本文介绍了在Swift上设置计时器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图重复执行pepe()函数,我没有收到任何错误,但没有用.

Im trying to execute the function pepe() repeated times, i get no errors but it doesnt work.

这是我的代码:

public class MyClass {
    var timer = Timer()
    @objc func pepe() -> String {
        let hola = "hola"
        return hola
    }
    func startTimer(){
         let seconds = 1.0
        timer = Timer.scheduledTimer(timeInterval: seconds, target: ().self, selector: #selector(pepe), userInfo: nil, repeats: false)

    }
    func stopTimer() {

        timer.invalidate()

    }

    init() {
        self.startTimer()
        self.stopTimer()
    }
}
var pepe = MyClass()
pepe.stopTimer()
pepe.startTimer()

推荐答案

我建议:

  1. 不要实例化一个空的Timer.考虑:

var timer = Timer()

正在创建一个空白计时器实例.我们不想这样做.您应该改用:

That is creating a blank timer instance. We don't want to do that. You should instead use:

weak var timer: Timer?

这实现了一些目的:

  • Timer?语法表示这是可选",您将在以后实例化其值.

  • The Timer? syntax says it's an "optional", whose value you will instantiate later.

安排了Timer时,runloop会对其保持强烈的引用.因此,与大多数其他对象不同,您个人不需要对计划的计时器保持严格的引用.并且您可能希望在计时器无效时将timer变量自动设置为nil.因此,weak限定词表示,当计时器无效时,timer变量将自动设置为nil.

When the Timer is scheduled, the runloop keeps a strong reference to it. So, unlike most other objects, you don't personally need to keep a strong reference to your scheduled timers. And you might want the timer variable to be automatically set to nil when the timer is invalidated. So, the weak qualifier says that when the timer is invalidated, the timer variable will automatically be set to nil.

pepe方法签名不太正确:

  • 它不应该返回任何内容;

  • It shouldn't return anything;

您可能应该给它一个Timer参数.养成良好的习惯.您在这里可能不需要它,但是它使方法的意图更加清楚,并且您最终可能会发现拥有该Timer参数很有用.和

You should probably give it the Timer parameter. It's a good habit to get into. You might not need it here, but it makes the intent of the method more clear and you may eventually find it useful to have that Timer parameter; and

为避免歧义,我可能会给它起一个更具描述性的名称.我倾向于使用timerHandler.

I might give it a more descriptive name to avoid any ambiguity; I tend to use names like timerHandler.

init中启动和停止计时器毫无意义.

There's no point in starting and stopping your timer in init.

target中对().self的引用应该只是self.

That reference to ().self in the target should just be self.

在操场上,您正在停止计时器(尚未安排开始计时),然后再启动它.

In your playground, you're stopping the timer (that hasn't been scheduled started yet) and then starting it.

您可能还需要一段时间后将其停止,因此您有机会看到正在使用的Timer.

You might also want to stop it after a little time, so you get a chance to see the Timer in action.

但是,作为一般规则,在编写启动计时器的方法时,请务必确保尚未(偶然地)启动计时器.如果您不这样做,并且不小心调用了startTimer两次,则最终可能同时运行多个计时器(更糟糕的是,丢失了对较早计时器的引用).一种常见的解决方案是,典型的解决方案是查看是否已经存在计时器,如果已存在,则在创建下一个计时器之前将其无效.这可以通过可选的链接模式轻松实现:

But, as general rule, when writing method to start the timer, it is prudent to make sure you hadn't (accidentally) already started it. If you don't do this, and accidentally call startTimer twice, you can end up with multiple timers going at the same time (and worst, having lost references to the earlier timers). One common solution typical solution is to see if there is a already timer, and if so, invalidate it before you create you next timer. This is easily accomplished with the optional chaining pattern:

func startTimer() {
    timer?.invalidate()   // stops previous timer, if any

    // now proceed with scheduling of new timer
}

因此:

import UIKit

// if doing this in playground, include the following two lines

import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

// MyClass

public class MyClass {
    weak var timer: Timer?

    @objc func timerHandler(_ timer: Timer) {
        let hola = "hola"
        print(">>>> \(hola)")
    }

    func startTimer() {
        timer?.invalidate()   // stops previous timer, if any

        let seconds = 1.0
        timer = Timer.scheduledTimer(timeInterval: seconds, target: self, selector: #selector(timerHandler(_:)), userInfo: nil, repeats: true)
    }

    func stopTimer() {
        timer?.invalidate()
    }
}

var object = MyClass()
object.startTimer()

// stop it 10 seconds later
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
    object.stopTimer()
}

但是,应该认识到,您可能会得到类似于强大参考周期的结果:

It should be recognized, though, that you can end up with something akin to a strong reference cycle:

  • runloop强烈引用计划的计时器;
  • 基于选择器的计时器对其target保持强烈引用;
  • MyClass(target)大概是导致该计时器最终失效的原因.
  • The runloop keeps a strong reference to scheduled timers;
  • The selector-based timer keeps strong reference to its target;
  • The MyClass (the target) is what presumably is responsible for eventually invalidating that timer.

结果,在Timer无效之前,无法释放MyClass.而且,就目前情况而言,您不能仅在MyClassdeinit中的invalidate Timer,因为在计时器无效之前,不会调用deinit.

As a result, MyClass can't be deallocated until the Timer is invalidated. And, as it stands, you cannot just invalidate the Timer in the deinit of MyClass, because deinit won't get called until the the timer is invalidated.

最终结果是,如果您将此MyClass作为视图控制器的属性,并启动计时器,然后关闭视图控制器,则计时器将继续运行,并且MyClass不会释放.

The net effect is that if you have, for example, this MyClass as a property of your view controller and start the timer and then dismiss the view controller, the timer will keep going and MyClass won't be deallocated.

要解决此问题,您可能希望将基于闭包的计时器与[weak self]引用一起使用,从而消除了计时器与MyClass之间的强引用.然后,您还可以在MyClass被释放后自动使计时器无效:

To solve this, you might want to use closure based timer with [weak self] reference, eliminating the strong reference between the timer and MyClass. You can then also automatically invalidate the timer when the MyClass is deallocated:

public class MyClass {
    weak var timer: Timer?

    deinit {
        timer?.invalidate()
    }

    func timerHandler(_ timer: Timer) {
        let hola = "hola"
        print(">>>> \(hola)")
    }

    func startTimer() {
        timer?.invalidate()   // stops previous timer, if any

        let seconds = 1.0
        timer = Timer.scheduledTimer(withTimeInterval: seconds, repeats: true) { [weak self] timer in
            self?.timerHandler(timer)
        }
    }

    func stopTimer() {
        timer?.invalidate()
    }
}

这篇关于在Swift上设置计时器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆