倒计时一般会想到用NSTimer(Timer)来计时,对于不是要非常精确地计时来说,已经够用了.这里也是用NSTimer(Timer)来计时的.在tableview上显示多个倒计时需要考虑用一个计时器还是每个cell都设置一个计时器.这里完成100毫秒(0.1秒)倒计时功能.
准备工作:Xcode8.2,swift3.0
1.使用一个计时器
先创建一个数据模型类,用于保存网络下载的数据.
如果需要倒计时,下载下来的数据肯定有一个时间结束的参数endTime
class TimeModel: NSObject {
var endTime:String? //结束时间,这是从网咯下载的数据
var leftTime:String? //剩余时间,根据endTime做相关处理,显示在cell上的倒计时
var remain:TimeInterval = 0.0//剩余时间
}
这里使用了storyboard创建控制器
@IBOutlet weak var tableView: UITableView!
var timer:Timer?
var dataArray = Array<TimeModel>()
这里模拟网络下载创建一些数据
//模拟数据
func createTime() {
//模拟网络请求数据
for _ in 0..<30 {
let M = arc4random()%12+1//月
var d = arc4random()%31+1//日
let h = arc4random()%24//小时
let m = arc4random()%60//分钟
let s = arc4random()%60//秒
//大小月纠正,这里是模拟数据,无需很严格
if M == 2 {
d = d >= 28 ? 28 : d
} else if M == 4 || M == 6 || M == 9 || M == 11 {
d = d >= 31 ? 30 : d
}
let model:TimeModel = TimeModel()
model.endTime = String(format: "2017-%02d-%02d %02d:%02d:%02d", M, d, h, m, s)
dataArray.append(model)
}
//对于下载的数据做初步处理
for model in dataArray {
let date = dateFormatter.date(from: model.endTime!)!
let leftTime = date.timeIntervalSinceNow
model.remain = leftTime > 0 ? leftTime : 0
//秒转时间
let ss = Int(model.remain)
let d = ss / (24*3600)
let h = ss % (24*3600) / 3600
let m = ss % 3600 / 60
let s = ss % 60
let u = (Int)(model.remain - Double(ss)) * 10
model.leftTime = String(format: "%03d天%02d:%02d:%02d.%d", d, h, m, s, u)
}
tableView.reloadData()
startTimer()
}
//开启计时器
func startTimer() {
if (timer != nil) {
timer!.invalidate()
timer = nil
}
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(refreshTime), userInfo: nil, repeats: true)
//默认加入到.defaultRunLoopMode,tableview滑动时会阻塞线程.
RunLoop.current.add(timer!, forMode: .commonModes)
}
//刷新时间界面
func refreshTime() {
var status = true //是否结束倒计时,true结束,false进行中
for i in 0..<dataArray.count {
let model = dataArray[i]
if model.remain > 0 {
status = false
if model.remain > 0.1 {
model.remain -= 0.1
//秒转时间
let ss = Int(model.remain)
let d = ss / (24*3600)
let h = ss % (24*3600) / 3600
let m = ss % 3600 / 60
let s = ss % 60
let u = (Int)((model.remain - Double(ss)) * 10)
model.leftTime = String(format: "%03d天%02d:%02d:%02d.%d", d, h, m, s, u)
} else {
model.remain = 0
model.leftTime = "000天00:00:00.0"
}
let cell = tableView.cellForRow(at: IndexPath(row: i, section: 0))
if cell != nil {
cell?.textLabel?.text = model.leftTime
}
}
}
if status {
timer?.invalidate()
timer = nil
}
}
```
//DateFormatter是比较消耗资源的,这里使用懒加载全局变量的形式创建
lazy var dateFormatter: DateFormatter = {
var dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return dateFormatter
}()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellId = "cellId"
var cell = tableView.dequeueReusableCell(withIdentifier: cellId)
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: cellId)
}
let model = dataArray[indexPath.row]
cell?.textLabel?.text = model.leftTime
return cell!
}
#####优化:
对于数据比较少且不用非常非常精确的计时功能,以上已经足够了.这里有几个可以优化的地方
######①筛选数据
将需要倒计时的数据保存在字典中,只对这些数据计时.这样对于数据量大的操作科技减少很多计算量.
//保存需要计时的数据
var dataDict = IndexPath:TimeModel
//数据处理时筛选出需要计时的数据
for i in 0..<dataArray.count {
let model = dataArray[i]
let date = dateFormatter.date(from: model.endTime!)!
let leftTime = date.timeIntervalSinceNow
//如果结束时间比现在时间早,剩余时间设为0
model.remain = leftTime > 0 ? leftTime : 0
if model.remain > 0 {
//秒转时间
let ss = Int(model.remain)
let d = ss / (243600)
let h = ss % (243600) / 3600
let m = ss % 3600 / 60
let s = ss % 60
let u = (Int)(model.remain - Double(ss)) * 10
model.leftTime = String(format: "%03d天%02d:%02d:%02d.%d", d, h, m, s, u)
let indexPath = IndexPath(row: i, section: 0)
dataDict[indexPath] = model
} else {
model.leftTime = "000天00:00:00.0"
}
func refreshTime() {
var status = true //是否结束倒计时,true结束,false进行中
for (indexPath, model) in dataDict {
if model.remain > 0 {
status = false
if model.remain > 0.1 {
model.remain -= 0.1
//秒转时间
let ss = Int(model.remain)
let d = ss / (24*3600)
let h = ss % (24*3600) / 3600
let m = ss % 3600 / 60
let s = ss % 60
let u = (Int)((model.remain - Double(ss)) * 10)
model.leftTime = String(format: "%03d天%02d:%02d:%02d.%d", d, h, m, s, u)
} else {
model.remain = 0
model.leftTime = "000天00:00:00.0"
dataDict.removeValue(forKey: indexPath)//如果计时结束,移除数据
}
let cell = tableView.cellForRow(at: indexPath)
if cell != nil {
cell?.textLabel?.text = model.leftTime
}
}
}
if status {
timer?.invalidate()
timer = nil
}
}
也可以
//保存需要计时的数据的IndexPath,获取dataArray中的model进行计算
var indexArray = Array<IndexPath>()
网友评论