I had tested this extensively in the past before starting the project I'm working on. I copied and pasted the code into my new project, so it should work. All I want it to do is reload the tableView every minute, so that the clocks displayed on the tableView reload.
func setMinutesForReload(){
//get calender object
let calender = Calendar.current
//curent date
let now = Date()
//create an array of dates to store minutes
var minutes = [Date]()
//timer array to store timers
var timers = [Timer]()
//set a run loop
for i in 0...23{
for j in 0...59{
minutes.append(calender.date(bySettingHour: i, minute: j, second: 0, of: now)!)
timers.append(Timer(fireAt: minutes[j], interval: 0, target: self, selector: #selector(minutelyReloadTimer), userInfo: nil, repeats: false))
RunLoop.main.add(timers[j], forMode: RunLoop.Mode.common)
}
}
}
@objc func minutelyReloadTimer(){
self.cityTableView.reloadData()
}
Oddly enough, when I run the app and set a breakpoint, I see that it calls minutelyReloadTimer() immediately, 59 times in a row (I counted).
Is this an issue with a recent Xcode/Swift update, or am I missing something that I'm not seeing?
CodePudding user response:
I'm certain the unexpected behavior you are witnessing is not due to an issue with Xcode/Swift.
Taking a look at your code, I noticed a couple strange things right off the bat. For one, RunLoop.main.add(timers[j]...
will only add timer's 0-59 to the run loop, over and over (24 times to be exact). And for two, calender.date(bySettingHour: i, minute: j, second: 0, of: now)
's default configuration is to find the next time that matches the given data components, since the function's last parameter (i.e. matchingPolicy: Calendar.MatchingPolicy
) is assigned a default value of .nextTime
. Therefore, the dates that will be returned are for tomorrow, not today.
Now, instead of dissecting your (unnecessarily complicated) method further, I would suggest a much simpler approach: fire a repeating 60 second timer, with the initial fire being on the start of the next minute.
In short, refactoring your code would result in the following.
func setMinutesForReload(){
//get calender object
let calender = Calendar.current
//curent date
let now = Date()
let dateOfNextMinute: Date = calender.nextDate(after: now, matching: DateComponents(second: 0), matchingPolicy: .nextTime)!
let timer = Timer(fireAt: dateOfNextMinute, interval: 60.0, target: self, selector: #selector(minutelyReloadTimer), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
}
@objc func minutelyReloadTimer(){
print("Reload")
}