有几个小数位的倒计时,在 Swift 中使用 NSTimer
Countdown with several decimal slots, using NSTimer in Swift
例如,我想制作一个具有从 10.0000000 开始的计时器的应用程序,并且我希望它能够完美倒计时
到目前为止,这是我的代码:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var labelTime: UILabel!
var counter = 10.0000000
var labelValue: Double {
get {
return NSNumberFormatter().numberFromString(labelTime.text!)!.doubleValue
}
set {
labelTime.text = "\(newValue)"
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
labelValue = counter
var timer = NSTimer.scheduledTimerWithTimeInterval(0.0000001, target: self, selector: ("update"), userInfo: nil, repeats: true)
}
func update(){
labelValue -= 0.0000001
}
}
发生的事情是我的倒计时真的很慢,它根本不起作用,需要 1 小时才能达到 0 秒,而不是仅仅 10 秒。有任何想法吗?我应该对我的代码进行哪些更改?
谢谢
计时器不是非常精确,NSTimer 的分辨率大约是 1/50 秒。
另外,iPhone 屏幕的刷新率是 60 frames/second,所以 运行 你的计时器再快一点都没有意义。
与其尝试使用计时器在每次触发时递减,不如创建一个每秒触发 50 次的计时器,并让它使用时钟数学根据剩余时间更新显示:
var futureTime: NSTimeInterval
override func viewDidLoad() {
super.viewDidLoad()
labelValue = counter
//FutureTime is a value 10 seconds in the future.
futureTime = NSDate.timeIntervalSinceReferenceDate() + 10.0
var timer = NSTimer.scheduledTimerWithTimeInterval(
0.02,
target: self,
selector: ("update:"),
userInfo: nil,
repeats: true)
}
func update(timer: NSTimer)
{
let timeRemaining = futureTime - NSDate.timeIntervalSinceReferenceDate()
if timeRemaining > 0.0
{
label.text = String(format: "%.07f", timeRemaining)
}
else
{
timer.invalidate()
//Force the label to 0.0000000 at the end
label.text = String(format: "%.07f", 0.0)
}
}
你想让它在一秒钟内显示 0.0000001 和 .99999999 之间的所有组合吗?屏幕实际上必须更新一亿次才能显示每个数字。在任何现有技术或可能的任何未来技术上,都没有可行的方法可以在一秒钟内完成此操作。屏幕本身的更新速度不能超过每秒 60 次,因此这是适合您的最快速度。
您可以尝试使用 NSTimer 获得该速率 (1/60 = 0.0167)。 NSTimer 本身不能保证非常精确。为了在每一帧更新屏幕,您必须使用 CADisplayLink
(https://developer.apple.com/library/ios/documentation/QuartzCore/Reference/CADisplayLink_ClassRef/).
这使您有机会 运行 在每次帧更新时选择器,这与系统根据定义更改帧的速度一样快。
例如,我想制作一个具有从 10.0000000 开始的计时器的应用程序,并且我希望它能够完美倒计时 到目前为止,这是我的代码:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var labelTime: UILabel!
var counter = 10.0000000
var labelValue: Double {
get {
return NSNumberFormatter().numberFromString(labelTime.text!)!.doubleValue
}
set {
labelTime.text = "\(newValue)"
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
labelValue = counter
var timer = NSTimer.scheduledTimerWithTimeInterval(0.0000001, target: self, selector: ("update"), userInfo: nil, repeats: true)
}
func update(){
labelValue -= 0.0000001
}
}
发生的事情是我的倒计时真的很慢,它根本不起作用,需要 1 小时才能达到 0 秒,而不是仅仅 10 秒。有任何想法吗?我应该对我的代码进行哪些更改? 谢谢
计时器不是非常精确,NSTimer 的分辨率大约是 1/50 秒。
另外,iPhone 屏幕的刷新率是 60 frames/second,所以 运行 你的计时器再快一点都没有意义。
与其尝试使用计时器在每次触发时递减,不如创建一个每秒触发 50 次的计时器,并让它使用时钟数学根据剩余时间更新显示:
var futureTime: NSTimeInterval
override func viewDidLoad() {
super.viewDidLoad()
labelValue = counter
//FutureTime is a value 10 seconds in the future.
futureTime = NSDate.timeIntervalSinceReferenceDate() + 10.0
var timer = NSTimer.scheduledTimerWithTimeInterval(
0.02,
target: self,
selector: ("update:"),
userInfo: nil,
repeats: true)
}
func update(timer: NSTimer)
{
let timeRemaining = futureTime - NSDate.timeIntervalSinceReferenceDate()
if timeRemaining > 0.0
{
label.text = String(format: "%.07f", timeRemaining)
}
else
{
timer.invalidate()
//Force the label to 0.0000000 at the end
label.text = String(format: "%.07f", 0.0)
}
}
你想让它在一秒钟内显示 0.0000001 和 .99999999 之间的所有组合吗?屏幕实际上必须更新一亿次才能显示每个数字。在任何现有技术或可能的任何未来技术上,都没有可行的方法可以在一秒钟内完成此操作。屏幕本身的更新速度不能超过每秒 60 次,因此这是适合您的最快速度。
您可以尝试使用 NSTimer 获得该速率 (1/60 = 0.0167)。 NSTimer 本身不能保证非常精确。为了在每一帧更新屏幕,您必须使用 CADisplayLink
(https://developer.apple.com/library/ios/documentation/QuartzCore/Reference/CADisplayLink_ClassRef/).
这使您有机会 运行 在每次帧更新时选择器,这与系统根据定义更改帧的速度一样快。