Timer.scheduledTimer 在 Swift 3 中不起作用
Posted
技术标签:
【中文标题】Timer.scheduledTimer 在 Swift 3 中不起作用【英文标题】:Timer.scheduledTimer does not work in 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()
方法调用它
【参考方案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)
【讨论】:
以上是关于Timer.scheduledTimer 在 Swift 3 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
使用蒸汽时 Timer.scheduledTimer 不可用?