ios Timer.scheduledTimer 在 Swift 3 中不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40613556/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Timer.scheduledTimer does not work in Swift 3
提问by Jing Bian
I want to call the method func adjustmentBestSongBpmHeartRate()
every 1.1 second. I used Timer, but it doesn't work. I have read the document and found a lot of sample code, it still does work! Is there anything I missed?
我想func adjustmentBestSongBpmHeartRate()
每 1.1 秒调用一次该方法。我使用了定时器,但它不起作用。我已经阅读了文档并找到了很多示例代码,它仍然有效!有什么我错过的吗?
timer = Timer.scheduledTimer(timeInterval: 1.1, target: self, selector: #selector(self.adjustmentBestSongBpmHeartRate), userInfo: nil, repeats: false)
timer.fire()
func adjustmentBestSongBpmHeartRate() {
print("frr")
}
回答by Nick H247
I found that creating the timer in an OperationQueue Operation did not work. I assume this is because there is no runloop.
我发现在 OperationQueue 操作中创建计时器不起作用。我认为这是因为没有运行循环。
Therefore, the following code fixed my problem:
因此,以下代码解决了我的问题:
DispatchQueue.main.async {
// timer needs a runloop?
self.timeoutTimer = Timer.scheduledTimer(timeInterval: self.timeout, target: self, selector: #selector(self.onTimeout(_:)), userInfo: nil, repeats: false)
}
回答by Duncan C
Timer methods with a selector are supposed to have one parameter: The timer itself. Thus your code should really look like this: 1
带有选择器的定时器方法应该有一个参数:定时器本身。因此你的代码应该是这样的:1
Timer.scheduledTimer(timeInterval: 1.1,
target: self,
selector: #selector(self.adjustmentBestSongBpmHeartRate(_:),
userInfo: nil,
repeats: false)
@objc func adjustmentBestSongBpmHeartRate(_ timer: Timer) {
print("frr")
}
Note that if your app only runs on iOS >= 10, you can use the new method that takes a block to invoke rather than a target/selector. Much cleaner and more type-safe:
请注意,如果您的应用程序仅在 iOS >= 10 上运行,您可以使用新方法,该方法需要调用块而不是目标/选择器。更干净,更安全:
class func scheduledTimer(withTimeInterval interval: TimeInterval,
repeats: Bool,
block: @escaping (Timer) -> Void) -> Timer
That code would look like this:
该代码如下所示:
timer = Timer.scheduledTimer(withTimeInterval: 1.1,
repeats: false) {
timer in
//Put the code that be called by the timer here.
print("frr")
}
Note that if your timer block/closure needs access to instance variables from your class you have to take special care with self
. Here's a good pattern for that sort of code:
请注意,如果您的计时器块/闭包需要访问您的类中的实例变量,您必须特别注意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
}
Edit:
编辑:
1: I should add that the method you use in the selector has to use Objective-C dynamic dispatch. You can declare the method with the @objc
qualifier, you can declare the entire class that defines the selector with the @objc
qualifier, or you can make the class that defines the selector a subclass of NSObject
or any class that inherits from NSOBject
. (It's quite common to define the method the timer calls inside a UIViewController
, which is a subclass of NSObject
, so it "just works".
1:我应该补充一点,您在选择器中使用的方法必须使用Objective-C 动态调度。您可以使用@objc
限定符声明方法,可以使用限定符声明定义选择器的整个类@objc
,或者可以使定义选择器的类成为 的子类NSObject
或任何继承自 的类NSOBject
。(在 a 中定义计时器调用的方法是很常见的,aUIViewController
是 的子类NSObject
,因此它“正常工作”。
EDIT
编辑
In Swift 4 methods that need to be called from Objective-C now need to be individually tagged with the @objc
qualifier. The "it just works" comment is no longer true.
在 Swift 中,需要从 Objective-C 调用的 4 个方法现在需要用@objc
限定符单独标记。“它只是有效”的评论不再正确。
回答by Jorge Casariego
Swift 3
斯威夫特 3
In my case it worked after I added to my method the @obj prefix
在我的情况下,它在我将@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
}
}
回答by Nikhil Manapure
Try this -
尝试这个 -
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)
}
Mostly the problem must have been because of iOS version of mobile.
大多数问题一定是因为移动设备的 iOS 版本。
回答by Jing Bian
I have solved the question asked by myself. I'm using apple watch to control my iphone app. I try to press a button on apple watch to present a new viewcontroller on iphone.
我已经解决了自己提出的问题。我正在使用 Apple Watch 来控制我的 iphone 应用程序。我尝试按下 Apple Watch 上的按钮以在 iphone 上显示一个新的视图控制器。
When I write Timer in override func viewDidLoad()
, Timer doesn't work. I move Timer to override func viewWillAppear()
it works.
当我在 中写入 Timer 时 override func viewDidLoad()
,Timer 不起作用。我将计时器移动到override func viewWillAppear()
它的工作原理。
I think maybe there's something wrong with controlling by apple watch
我想可能是 Apple Watch 控制有问题
回答by Mark A. Donohoe
I found that if you try to initialize the timer directly at the class-level, it won't work if you're targeting a selector in that same class. When it fires, it can't find the selector.
我发现如果您尝试直接在类级别初始化计时器,如果您针对的是同一类中的选择器,它将无法工作。当它触发时,它找不到选择器。
To get around this, I only initialize the timer afterthe object containing the selector has been initialized. If it's in the same class, put the initialization code in the ViewDidLoad
or similar. Just not in the initializer. Then it will work. No dispatch queue needed.
为了解决这个问题,我只在初始化包含选择器的对象之后才初始化计时器。如果在同一个类中,将初始化代码放在ViewDidLoad
或类似的地方。只是不在初始化程序中。然后它会起作用。不需要调度队列。
Also, you do notneed to use a selector that accepts the timer as a parameter. You can, but contrary to the answer with a ton of votes, that's not actually true, or more specifically, it works fine for me without it, just as you have it without it.
此外,你也不会需要使用接受的计时器作为参数选择。你可以,但与大量选票的答案相反,这实际上不是真的,或者更具体地说,没有它对我来说很好,就像没有它一样。
By the way, I think the reason the dispatch queue worked is because you're forcing the timer to be created after the object was initializing, confirming my above statement.
顺便说一句,我认为调度队列工作的原因是因为您在对象初始化后强制创建计时器,这证实了我的上述说法。
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")
}
Note: This is code typed from memory, not copied from Xcode so it may not compile, but hopefully you get the idea.
注意:这是从内存中键入的代码,不是从 Xcode 复制的,因此它可能无法编译,但希望您能理解。
回答by Shakeel Ahmed
Swift 5, Swift 4 Simple way only call with Dispatch Queue Async
Swift 5, Swift 4 简单的方法只用调度队列异步调用
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)
})
}
回答by user3711263
Swift3
斯威夫特3
var timer = Timer()
timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.compruebaConexion), userInfo: nil, repeats: true)
回答by ingconti
my two cents. I read about "didLoad" and when invoking it. so we can use a delay:
我的两分钱。我阅读了“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)
}