Swift - 使用UIDatePicker实现倒计时功能
(本文代码已升级至Swift4)

下面是代码示例:
import UIKit
class ViewController: UIViewController {
var ctimer:UIDatePicker!
var btnstart:UIButton!
var leftTime:Int = 180
var alertController:UIAlertController!
var timer:Timer!
override func viewDidLoad() {
super.viewDidLoad()
ctimer = UIDatePicker(frame:CGRect(x:0, y:120, width:200, height:200))
self.ctimer.datePickerMode = UIDatePickerMode.countDownTimer
//必须为 60 的整数倍,比如设置为100,值自动变为 60
self.ctimer.countDownDuration = TimeInterval(leftTime);
ctimer.addTarget(self, action: #selector(ViewController.timerChanged),
for: .valueChanged)
self.view.addSubview(ctimer)
btnstart = UIButton(type: .system)
btnstart.frame = CGRect(x:100, y:400, width:100, height:100);
btnstart.setTitleColor(UIColor.red, for: .normal)
btnstart.setTitleColor(UIColor.green, for:.disabled)
btnstart.setTitle("开始", for:.normal)
btnstart.setTitle("倒计时中", for:.disabled)
btnstart.clipsToBounds = true
btnstart.layer.cornerRadius = 5
btnstart.addTarget(self, action:#selector(ViewController.startClicked),
for:.touchUpInside)
self.view.addSubview(btnstart)
}
@objc func timerChanged()
{
print("您选择倒计时间为:\(self.ctimer.countDownDuration)")
}
/**
*开始倒计时按钮点击
*/
@objc func startClicked(sender:UIButton)
{
self.btnstart.isEnabled = false
// 获取该倒计时器的剩余时间
leftTime = Int(self.ctimer.countDownDuration);
// 禁用UIDatePicker控件和按钮
self.ctimer.isEnabled = false
// 创建一个UIAlertController对象(警告框),并确认,倒计时开始
alertController = UIAlertController(title: "系统提示",
message: "倒计时开始,还有 \(leftTime) 秒...",
preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "确定", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
// 显示UIAlertController组件
self.present(alertController, animated: true, completion: nil)
// 启用计时器,控制每秒执行一次tickDown方法
timer = Timer.scheduledTimer(timeInterval: TimeInterval(1), target:self,
selector:#selector(ViewController.tickDown),
userInfo:nil,repeats:true)
}
/**
*计时器每秒触发事件
**/
@objc func tickDown()
{
alertController.message = "倒计时开始,还有 \(leftTime) 秒..."
// 将剩余时间减少1秒
leftTime -= 1;
// 修改UIDatePicker的剩余时间
self.ctimer.countDownDuration = TimeInterval(leftTime);
print(leftTime)
// 如果剩余时间小于等于0
if(leftTime <= 0)
{
// 取消定时器
timer.invalidate();
// 启用UIDatePicker控件和按钮
self.ctimer.isEnabled = true;
self.btnstart.isEnabled = true;
alertController.message = "时间到!"
}
}
}
上面的代码其实还是有个小bug的。
(1)问题描述:代码中给时间控件添加了个 ValueChanged 事件监听响应,目的是想每次选择的时间改变时都会触发打印出时间。但运行会发现,第一次拨动表盘不触发,后面再改变值才会触发。
(2)解决办法:这个是iOS的bug,我们把设置初始时间代码
//必须为 60 的整数倍,比如设置为100,值自动变为 60 self.ctimer.countDownDuration = TimeInterval(leftTime)修改成
DispatchQueue.main.async{
self.ctimer.countDownDuration = TimeInterval(self.leftTime)
}
(如果我们不需要关心值改变事件的话,直接用原来的赋值方法即可。)

func timerChanged()没起作用
本人以学习的态度,将程序敲进xcode,显示以下问题,有异常需要处理,由于本人太菜,希望站长给予帮助!谢谢!
2015-11-12 15:31:58.689 Timer_crash[2103:160516] -[Timer_crash.ViewController startClicked:]: unrecognized selector sent to instance 0x7fad326a1ec0
2015-11-12 15:31:58.700 Timer_crash[2103:160516] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Timer_crash.ViewController startClicked:]: unrecognized selector sent to instance 0x7fad326a1ec0'
*** First throw call stack:
(
0 CoreFoundation 0x0000000100fd9f45 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000102cfddeb objc_exception_throw + 48
2 CoreFoundation 0x0000000100fe256d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x0000000100f2feea ___forwarding___ + 970
4 CoreFoundation 0x0000000100f2fa98 _CF_forwarding_prep_0 + 120
5 UIKit 0x00000001017f7e91 -[UIApplication sendAction:to:from:forEvent:] + 92
6 UIKit 0x00000001019634d8 -[UIControl sendAction:to:forEvent:] + 67
7 UIKit 0x00000001019637a4 -[UIControl _sendActionsForEvents:withEvent:] + 311
8 UIKit 0x00000001019628d4 -[UIControl touchesEnded:withEvent:] + 601
9 UIKit 0x0000000101865ed1 -[UIWindow _sendTouchesForEvent:] + 835
10 UIKit 0x0000000101866c06 -[UIWindow sendEvent:] + 865
11 UIKit 0x00000001018162fa -[UIApplication sendEvent:] + 263
12 UIKit 0x00000001017f0abf _UIApplicationHandleEventQueue + 6844
13 CoreFoundation 0x0000000100f06011 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
14 CoreFoundation 0x0000000100efbf3c __CFRunLoopDoSources0 + 556
15 CoreFoundation 0x0000000100efb3f3 __CFRunLoopRun + 867
16 CoreFoundation 0x0000000100efae08 CFRunLoopRunSpecific + 488
17 GraphicsServices 0x00000001055cdad2 GSEventRunModal + 161
18 UIKit 0x00000001017f630d UIApplicationMain + 171
19 Timer_crash 0x0000000100dfa15d main + 109
20 libdyld.dylib 0x000000010380592d start + 1
21 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
倒计时的选择器,不显示秒
结果把180改成10秒,警告框显示的是从60秒开始读