Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIDate Picker valuechanged does not update the first spin, but does every spin after.. iOS

Tags:

ios

datepicker

I have a UIDate Picker embedded in a static TableViewCell and at the moment I disabled most of the code except the code responsible for the date picker.

I'm using the Date Picker as a Count Down Timer

So this is kind of all, except some usual outlets and vars:

override func viewDidLoad() {
    super.viewDidLoad()

    //  tfName.delegate = self
    //  tfDescription.delegate = self
    //

    datePicker.countDownDuration = 60

    //  pickerValueChanged(self)

}


@IBAction func pickerValueChanged(sender: AnyObject) {

     seconds  = Int(datePicker.countDownDuration)
     hours  = seconds / 3600
    if hours == 0{
        minutes = seconds / 60
    } else{
        minutes = seconds % 3600 / 60
    }
    labelDuration.text = "\(hours) hours \(minutes) minutes"
}

The first time I change the value of the Picker, the value changed function does not fire at all, but the spins after it does without failing.

I tried to call it in viewDidLoad, with pickerValueChanged(self) and that works, but does not solve the problem. Also I commented out every line of code in the pickerValueChanged function and viewDidLoad but it still did not fire the first spin..

Thank you for your time!

Update: Added pictures

After the first spin, pickerValueChanged does not get called: First spin

From the second spin and beyond, the event gets called and the label is updated: Second spin

Tried:

Executing: datePicker.setDate(NSDate(), animated: true in viewDidLoad() solves the problem that the event doesn't get called at the first spin, but this sets the initial state of the Date Picker to the current time. Since I'm using this control to set a duration to a event, I want to let it start at 0 hour and 1 minute. This can be done with datePicker.countDownDuration = 60 but after this, the main problem gets back again. So a solution could be setting the DatePicker with a NSDate of 1 minute, but how to do this?

Solution:

var dateComp : NSDateComponents = NSDateComponents()
dateComp.hour = 0
dateComp.minute = 1
dateComp.timeZone = NSTimeZone.systemTimeZone()
var calendar : NSCalendar = NSCalendar(calendarIdentifier: NSGregorianCalendar)!
var date : NSDate = calendar.dateFromComponents(dateComp)!

datePicker.setDate(date, animated: true)
like image 396
Henk-Martijn Avatar asked Feb 03 '15 09:02

Henk-Martijn


6 Answers

I came up the following solution to initialize the datePicker component (in countdown timer mode) with 0 hours and 1 minute and it responds directly at the first spin. Since this appears to be a bug and is very frustrating if you want a textlabel to update its value when the datePicker is changed and it does not at the first go:

var dateComp : NSDateComponents = NSDateComponents()
dateComp.hour = 0
dateComp.minute = 1
dateComp.timeZone = NSTimeZone.systemTimeZone()
var calendar : NSCalendar = NSCalendar(calendarIdentifier: NSGregorianCalendar)!
var date : NSDate = calendar.dateFromComponents(dateComp)!

datePicker.setDate(date, animated: true)

The timeZone component is not really needed for this to work for my implementation.

like image 96
Henk-Martijn Avatar answered Nov 17 '22 12:11

Henk-Martijn


It seems to be something to do with the animated parameter. You just need this line:

datePicker.setDate(date, animated: true)
like image 37
Mathias Claassen Avatar answered Nov 17 '22 14:11

Mathias Claassen


Time ago I found another problem that somehow resembles this one. It was about presenting a view controller from within the tableView:didSelectRowAtIndexPath: and the problem was that it was taking lots of time for the new controller to actually show up. One of the workarounds turned out to be using dispatch_async on the main queue. The same worked for me in this case.

In my viewDidLoad, I asynchronously dispatched the picker setup code on the main queue and, in my case, it started to respond to the valueChanged event even on the first pick:

DispatchQueue.main.async {
    self.pickerView.datePickerMode = .countDownTimer
    self.pickerView.minuteInterval = 5
    self.pickerView.countDownDuration = 15
}
like image 41
Marcin Czenko Avatar answered Nov 17 '22 12:11

Marcin Czenko


Here's @Henk-Martijn's solution updated & simplified for Swift 3:

let calendar = Calendar(identifier: .gregorian)
let date = DateComponents(calendar: calendar, hour: 1, minute: 30).date!
datePicker.setDate(date, animated: true)

Use the above code instead of something like:

datePicker.countDownDuration = 5_400
like image 29
Jeehut Avatar answered Nov 17 '22 13:11

Jeehut


Similar problem as above, I used

DispatchQueue.main.asyncAfter(deadline: .now()) {
   self.datePicker.countDownDuration = 60
}

to put it on the next runloop. Seems a viable workaround.

like image 3
JeffL Avatar answered Nov 17 '22 12:11

JeffL


I think you should try implement this delegate instead

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
like image 1
dminones Avatar answered Nov 17 '22 13:11

dminones