timerswift4.1

Best way to fire a function when current time reaches a specific time


Hey I want to change my Application's mode from Day to Night when the device's clock hits 6 pm and change it again when clocks hits 6 am. Right now I am using Timer every second to check the time and fire my functions. But I feel it's not the best method.


Solution

  • Hello yes your method is not the best way, as that will consume user's device Battery Life. I applied one trick in my project. You can do one thing, when your application starts, check if the "Specific time" has reached. And You would also need to check it when device "Time zone" or "Clock time" changes.

    func checkTimeToFireMethod(){
    
            let calendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)!
            let date = Date()
            calendar.locale = Locale(identifier: "en_US_POSIX")
            let hour = calendar.component(.hour, from: date)
            let minutes = calendar.component(.minute, from: date)
            let seconds = calendar.component(.second, from: date)
            let timeNowInSeconds = seconds + minutes*60 + hour*3600
            var timeLeft = 0
            // 6 am (06:00:00) changes to seconds (6*3600) and current time in seconds. here we are checking if the current time is less than 6:00:00 am
            if timeNowInSeconds < 6*3600{
                timeLeft = 6*3600 - timeNowInSeconds
            }
            // 6 pm (18:00:00) changes to seconds (18*3600) and current time in seconds. here we are checking if the current time is between  6:00:00 am and 6:00:00 pm.
            if timeNowInSeconds < 18*3600 && timeNowInSeconds >= 6*3600{
                 timeLeft = 18*3600 - timeNowInSeconds
    
            }
            // 6 pm (18:00:00) changes to seconds (18*3600) and current time in seconds. here we are checking if the current time is greater than  6:00:00 am and 6:00:00 pm.
            else if timeNowInSeconds >= 18*3600{
                timeLeft = 24*3600 - timeNowInSeconds
            }
    
            // to avoid any descripancy
            // check 30 seconds prior to actual time
            self.perform(#selector(self.myFuncation), with: nil, afterDelay: TimeInterval(timeLeft - 30))
            // check on time
            self.perform(#selector(self.myFuncation), with: nil, afterDelay: TimeInterval(timeLeft))
    
            // check 30 seconds after  actual time
            self.perform(#selector(self.myFuncation), with: nil, afterDelay: TimeInterval(timeLeft + 30))
        }
    

    And then call your function to perform your task

    func myFuncation(){
    } 
    

    Also add following Notifications :-

         NotificationCenter.default.addObserver(self, selector: #selector(self.checkTimeToFireMethod), name: NSNotification.Name.NSSystemClockDidChange, object: nil)
       NotificationCenter.default.addObserver(self, selector: #selector(self.checkTimeToFireMethod), name: NSNotification.Name.NSSystemTimeZoneDidChange, object: nil)