定时器 and/or RunLoop 的错误?
Bug with Timer and/or RunLoop?
在开始我正在进行的项目之前,我过去曾对此进行过广泛的测试。我将代码复制并粘贴到我的新项目中,所以它应该可以工作。我想让它做的就是每分钟重新加载 tableView,以便重新加载 tableView 上显示的时钟。
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()
}
奇怪的是,当我 运行 应用程序并设置断点时,我看到它立即调用 minutelyReloadTimer(),连续 59 次(我数过)。
这是最近 Xcode/Swift 更新的问题,还是我遗漏了一些我没有看到的东西?
我确定您看到的意外行为不是由于 Xcode/Swift 的问题。
查看您的代码,我立即注意到一些奇怪的事情。首先,RunLoop.main.add(timers[j]...
只会将计时器的 0-59 添加到 运行 循环中,一遍又一遍(准确地说是 24 次)。对于两个,calender.date(bySettingHour: i, minute: j, second: 0, of: now)
的默认配置是查找下一次匹配给定数据组件的时间,因为函数的最后一个参数(即 matchingPolicy: Calendar.MatchingPolicy
)被分配了默认值 .nextTime
.因此,返回的日期是明天,而不是今天。
现在,我不会进一步剖析您的(不必要的复杂)方法,而是建议一种更简单的方法:重复启动 60 秒计时器,并在下一分钟开始启动。
简而言之,重构您的代码会产生以下结果。
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")
}
在开始我正在进行的项目之前,我过去曾对此进行过广泛的测试。我将代码复制并粘贴到我的新项目中,所以它应该可以工作。我想让它做的就是每分钟重新加载 tableView,以便重新加载 tableView 上显示的时钟。
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()
}
奇怪的是,当我 运行 应用程序并设置断点时,我看到它立即调用 minutelyReloadTimer(),连续 59 次(我数过)。
这是最近 Xcode/Swift 更新的问题,还是我遗漏了一些我没有看到的东西?
我确定您看到的意外行为不是由于 Xcode/Swift 的问题。
查看您的代码,我立即注意到一些奇怪的事情。首先,RunLoop.main.add(timers[j]...
只会将计时器的 0-59 添加到 运行 循环中,一遍又一遍(准确地说是 24 次)。对于两个,calender.date(bySettingHour: i, minute: j, second: 0, of: now)
的默认配置是查找下一次匹配给定数据组件的时间,因为函数的最后一个参数(即 matchingPolicy: Calendar.MatchingPolicy
)被分配了默认值 .nextTime
.因此,返回的日期是明天,而不是今天。
现在,我不会进一步剖析您的(不必要的复杂)方法,而是建议一种更简单的方法:重复启动 60 秒计时器,并在下一分钟开始启动。
简而言之,重构您的代码会产生以下结果。
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")
}