0

I am trying to add a feature where someone will select a time form a UIDatePicker. Once the current time and the time that is selected match up, code will be executed. This sounds fairly simple when typed out but my code is a mess.

I have tried to use a timer to update the code every second to see if the selected time matches the iPhones internal clock. This however has not worked successfully with my code. The code that i wrote set a timer in increments of 1 minute. If the time is 9:30:21 and you select 9:31, instead of the code executing at 9:31 it executes at 9:31:21. Here is my code, any help is greatly appreciated.

@IBAction func datePickerchanged(_ sender: Any) {
    setDateAndTime()
    check()
    timercount = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(check), userInfo: nil, repeats: true)
    _ = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(check), userInfo: nil, repeats: true)

    let clockString: String = formatADate()

    if str == clockString{
        takePhoto = true
    }
}


func update(_ currentTime: TimeInterval) {
    let clockString: String = formatADate()
    if str == clockString{
        takePhoto = true

    }
}
func refreshView () {
    let clockString: String = formatADate()
    if str == clockString{
        takePhoto = true
    }

}
func check() {
    let fireDate = datePicker.date

    if fireDate < Date() {
        takePhoto = true
    }
}

func setDateAndTime() {
    check()
    timercount = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(check), userInfo: nil, repeats: true)
    let formatter = DateFormatter()
    formatter.dateFormat = "hh:mm:ss a"
    _ = formatter.string(from: datePicker.date)
    str = dateFormatter.string(from: (datePicker?.date)!)
}
func formatADate() -> String {
    let dateFormatter = DateFormatter()
    dateFormatter.dateStyle = .short
    dateFormatter.dateFormat = "hh:mm:ss a"
    let date = NSDate()
    let output = dateFormatter.string(from: date as Date)
    print(output)
    return output
}

I tried using this code:

func check() {
        let fireDate = datePicker.date
        let timer = Timer(timeInterval: fireDate, target: self, selector: Selector(take), userInfo: 0, repeats: false)
        RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)
        if fireDate < Date() {
            takePhoto = true
        }
    }
    func take() {
        takePhoto = true
    }

but i get an error cannot convert value type 'date' to expected argument type 'timeinterval' (aka 'double')

  • Please do not repeat your own question http://stackoverflow.com/questions/42603809/compare-selected-time-to-current-time – matt Mar 06 '17 at 03:05
  • Why do you want to check every second when the only matching time is already known? Use a repeating timer that fires at the earliest matching time. For example, if the user selects 16:00 and it is now 15:00, the earliest matching time is today at 16:00. So set the timer to fire then. When the timer fires, there will be nothing to compare: that is the moment, right then. – matt Mar 06 '17 at 03:07
  • 1
    @matt if you have read my other question you would see that they are diffferent from each other. I do not like it when other people ask the same question again and again and I am not a hypocrite. The second comment you posted sounds correct, but I am not sure what I did wrong, could you please post an answer with the correct code or at least edit you comment to show me where I have a problem. –  Mar 06 '17 at 03:25
  • I am suggesting that the entire idea of checking every second to see if now is the time is itself a problem. – matt Mar 06 '17 at 03:27
  • So what could i do instead of checking every second –  Mar 06 '17 at 03:28
  • What I said. You know what the earliest matching time is, so just make a timer that fires _then_. – matt Mar 06 '17 at 04:33
  • 1
    Please create an answer instead of filling up the comments section @matt – Oren Edrich Mar 06 '17 at 05:07

1 Answers1

1

You can simply schedule a timer to fire at the date given by the picker.

let timer = Timer(fireAt: fireDate, interval: 0, target: self, selector: #selector(<a selector you want to use...>), repeats: false)
RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)

So, simply pass in the picker date in the "fireAt" parameter and the timer will fire at that date and run the selector you provide.

zumzum
  • 17,984
  • 26
  • 111
  • 172
  • Is it possible to set a timer for zero seconds in order to execute the code at that specific time or would I have to set the timer for longer – Oren Edrich Mar 06 '17 at 14:26
  • @OrenEdrich Don't use a timer for that case, you can simply check when you want to set the timer if the date is "now", if so you can call the selector immediately, otherwise set the timer instead. – zumzum Mar 06 '17 at 15:28
  • So I should set the selector to a function I want to run and it will call it at the right time? – Oren Edrich Mar 06 '17 at 15:29
  • @OrenEdrich yes, when you don't need the timer to call the function just call it directly. When you need a timer because the date is not "now" then just have the timer's selector call the function. – zumzum Mar 06 '17 at 16:34
  • @zumzum i just realized i get an error, i added it to my question under i tried this code –  Mar 06 '17 at 17:04
  • @voodoo that is just an example... the date there needs to be a time interval, so if the date you're getting from the date picker is "myDate", then you can pass in "myDate.timeIntervalSinceNow" to the "fireAt" argument. – zumzum Mar 06 '17 at 17:17
  • you forgot `userInfo` param – Vyachaslav Gerchicov Apr 23 '21 at 06:12