Swift - 防止计时器重复
Swift - Prevent timer duplicating
我有一个在 viewDidLoad 中运行的计时器
_ = Timer.scheduledTimer(timeInterval: 10,
target: self,
selector: #selector(timerFired),
userInfo: nil,
repeats: true)
计时器工作正常,问题是因为多次调用 viewDidLoad,计时器重复。
有什么方法可以确保我的计时器只 运行 一次吗?
viewDidLoad 方法在视图控制器的生命周期内只被调用一次。
如果您有多个计时器 运行 那么您可能有多个视图控制器实例。否则,当您将视图控制器从导航堆栈中弹出并且您的计时器试图再次调用它时,您可能会崩溃。
您需要通过释放它们来平衡您在 viewDidLoad 中创建的内容。
编辑:
通常,您通过将清理代码放入 deinit
方法来平衡您在 viewDidLoad 中创建的内容。但是,看起来 运行 计时器保持对其目标的强引用。因此,如果您的视图控制器是 运行 计时器的目标,那么它的 deinit 方法将不会被调用。
我建议在 viewWillAppear 中创建计时器并在 viewWillDisappear 中使其无效:
weak var timer: Timer?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
timer = Timer.scheduledTimer(timeInterval: 1.0,
target: self,
selector: #selector(timerFired(timer:)),
userInfo: nil, repeats: true)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
timer?.invalidate()
}
编辑#2:
或者,您可以使用新的 iOS 10 版本的 scheduledTimer(),它采用 block 而不是 target/selector。 最终 Apple 创建了此功能。该死的时间到了!
weak var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(withTimeInterval: 1.0,
repeats: true) {
[weak self] timer in
//Your timer code here
}
deinit {
timer?.invalidate()
}
您需要保留对计时器的引用,以便在 viewController 消失时使它失效。否则它只会保留 运行 并且每次创建另一个 viewController 时都会产生新的计时器。
var timer:Timer?
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 1,
target: self,
selector: #selector(timerFired),
userInfo: nil,
repeats: true)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if let timer = timer {
timer.invalidate()
}
}
根据您的导航逻辑,viewWillDisappear
可能会在视图被释放之前被多次调用,您必须自己决定最佳的处理方式。
我有一个在 viewDidLoad 中运行的计时器
_ = Timer.scheduledTimer(timeInterval: 10,
target: self,
selector: #selector(timerFired),
userInfo: nil,
repeats: true)
计时器工作正常,问题是因为多次调用 viewDidLoad,计时器重复。
有什么方法可以确保我的计时器只 运行 一次吗?
viewDidLoad 方法在视图控制器的生命周期内只被调用一次。
如果您有多个计时器 运行 那么您可能有多个视图控制器实例。否则,当您将视图控制器从导航堆栈中弹出并且您的计时器试图再次调用它时,您可能会崩溃。
您需要通过释放它们来平衡您在 viewDidLoad 中创建的内容。
编辑:
通常,您通过将清理代码放入 deinit
方法来平衡您在 viewDidLoad 中创建的内容。但是,看起来 运行 计时器保持对其目标的强引用。因此,如果您的视图控制器是 运行 计时器的目标,那么它的 deinit 方法将不会被调用。
我建议在 viewWillAppear 中创建计时器并在 viewWillDisappear 中使其无效:
weak var timer: Timer?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
timer = Timer.scheduledTimer(timeInterval: 1.0,
target: self,
selector: #selector(timerFired(timer:)),
userInfo: nil, repeats: true)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
timer?.invalidate()
}
编辑#2:
或者,您可以使用新的 iOS 10 版本的 scheduledTimer(),它采用 block 而不是 target/selector。 最终 Apple 创建了此功能。该死的时间到了!
weak var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(withTimeInterval: 1.0,
repeats: true) {
[weak self] timer in
//Your timer code here
}
deinit {
timer?.invalidate()
}
您需要保留对计时器的引用,以便在 viewController 消失时使它失效。否则它只会保留 运行 并且每次创建另一个 viewController 时都会产生新的计时器。
var timer:Timer?
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 1,
target: self,
selector: #selector(timerFired),
userInfo: nil,
repeats: true)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if let timer = timer {
timer.invalidate()
}
}
根据您的导航逻辑,viewWillDisappear
可能会在视图被释放之前被多次调用,您必须自己决定最佳的处理方式。