Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
iOS UIDatePicker in UIDatePickerMode.countDownTimer value changed bug
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Create a DatePicker
let datePicker: UIDatePicker = UIDatePicker()
// Posiiton date picket within a view
datePicker.frame = CGRect(x: 10, y: 50, width: self.view.frame.width, height: 200)
// Set some of UIDatePicker properties
datePicker.backgroundColor = UIColor.white
datePicker.datePickerMode = UIDatePickerMode.countDownTimer;
// Add an event to call onDidChangeDate function when value is changed.
datePicker.addTarget(self, action: #selector(ViewController.datePickerValueChanged(_:)), for: .valueChanged)
// Add DataPicker to the view
self.view.addSubview(datePicker)
}
// Not called the first time
func datePickerValueChanged(_ sender: UIDatePicker){
print("Selected value \(sender.countDownDuration)")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
@yuv4ik
Copy link
Author

yuv4ik commented Mar 20, 2017

Just reported to Apple.

@lordzsolt
Copy link

lordzsolt commented Nov 3, 2021

It's 2021. Bug still there...

The only way I found to work around it is to start a timer in viewDidLoad, that calls datePickerValueChanged, and invalidate the timer once the sender is not nil.

Something like:

// Optional sender, so we can call it ourselves
func datePickerValueChanged(_ sender: UIDatePicker?) {
    let selectedValue: TimeInterval
    
    if let sender = sender {
        // Called by UIKit, UIDatePicker works, we no longer need the timer
        timer.invalidate()
        selectedValue = sender.countDownDuration
   } else {
       // Called by the timer, read the current value of the datePicker, because it's accurate, only the `.valueChanged` event is not fired
       selectedValue = datePicker.countDownDuration
   }
   
    print("Selected value \(sender.countDownDuration)")
}

func viewDidLoad() {
        // Set a very small interval, so we read the value often, in case the screen closes for example
        self.timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true, block: { [weak self] _ in
            self?.datePickerValueChanged(nil)
        })
}

@demirciy
Copy link

demirciy commented Apr 5, 2022

Thanks @lordzsolt , your solution is working.

It is weird this bug is still alive 👎

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment