IOS:使用NSTimer更新UITableViewCell中的标签

时间:2015-04-16 17:42:35

标签: ios uitableview swift nstimer

我正在尝试创建一个倒计时应用程序,它将显示年数......秒数,直到即将到来的日期。我希望能够在表格视图中查看多个倒计时。我有一些基本逻辑,它独立于tableview单元格来创建倒计时:

.
.
.
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "countdown", userInfo: nil, repeats: true)

func  countdown() {
    let hourMinuteComponents: NSCalendarUnit =
        NSCalendarUnit.CalendarUnitYear |
        NSCalendarUnit.CalendarUnitMonth |
        NSCalendarUnit.CalendarUnitDay |
        NSCalendarUnit.CalendarUnitHour |
        NSCalendarUnit.CalendarUnitMinute |
        NSCalendarUnit.CalendarUnitSecond
    let timeDifference = userCalendar.components(
        hourMinuteComponents,
        fromDate: NSDate(),
        toDate: date1.enteredDate as NSDate,
        options: nil)
// Sample Output
    println("Year: \(timeDifference.year)")
    println("Month: \(timeDifference.month)")
    println("Day: \(timeDifference.day)")
    println("Hour: \(timeDifference.hour)")
    println("Minute: \(timeDifference.minute)")
    println("Second: \(timeDifference.second)")
}

效果很好,控制台显示倒计时。但是,当我尝试从单元格中调用它时,我无法通过错误。

  

由于未捕获的异常而终止应用   'NSInvalidArgumentException',原因:' - [__ NSCFTimer row]:   无法识别的选择器发送到实例

这是不起作用的代码。

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    println("Index Path: \(indexPath)")
    let cell = tableView.dequeueReusableCellWithIdentifier("countDownCell") as! UITableViewCell
    let cellIndex = indexPath
    var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "update:", userInfo: cellIndex, repeats: true)
    //let secondlabel = cell.viewWithTag(1005) as! UILabel
    //secondlabel.text = "Test"


    return cell

}


func  update(cellIndex: NSIndexPath) {
    let hourMinuteComponents: NSCalendarUnit =
    NSCalendarUnit.CalendarUnitYear |
    NSCalendarUnit.CalendarUnitMonth |
    NSCalendarUnit.CalendarUnitDay |
        NSCalendarUnit.CalendarUnitHour |
        NSCalendarUnit.CalendarUnitMinute |
        NSCalendarUnit.CalendarUnitSecond
    let timeDifference = userCalendar.components(
        hourMinuteComponents,
        fromDate: NSDate(),
        toDate: date1.enteredDate as NSDate,
        options: nil)
    println("Year: \(timeDifference.year)")
    println("Month: \(timeDifference.month)")
    println("Day: \(timeDifference.day)")
    println("Hour: \(timeDifference.hour)")
    println("Minute: \(timeDifference.minute)")
    println("Second: \(timeDifference.second)")


    if let cell = tableView.cellForRowAtIndexPath(cellIndex) {
        let yearlabel = cell.viewWithTag(1000) as! UILabel
        let secondlabel = cell.viewWithTag(1005) as! UILabel!
    }

    secondlabel.text = "\(timeDifference.second)"


}

感谢您提供的任何帮助。我最初把我的修复尝试集中在改变我从计时器调用update()的方式。我尝试显式传递单元格然后认为最好尝试调用单元格的indexPath。我也按照许多NSTimer帖子中的建议检查了我的语法。我认为我做得对(并且相信我已经尝试了很多其他选项)。

代码在此行中断:

if let cell = tableView.cellForRowAtIndexPath(cellIndex) { ...

3 个答案:

答案 0 :(得分:7)

我建议您采用不同的方法来构建应用。

UITableView将使用dequeueReusableCellWithIdentifier方法“回收”其单元格。因此,如果用户要使用您的应用程序创建100个倒计时,但屏幕上最多只能看到4个单元格,当用户滚动时,这四个单元格将被排入表格视图的单元格缓存中,然后由您的数据出列源代码。这样做是为了提高性能,使表格视图平滑滚动。您可以在Apple的Table View Programming Guide中了解有关此行为的更多信息。

如果是我......

  1. 我首先要有一个可以跟踪倒计时状态的对象:倒计时开始日期,倒计时结束日期,倒计时名称等。

  2. 我将这些对象的数组用作表视图所代表的数据。

  3. 由于 all 倒计时每秒更新一次,您可以通过询问表格视图当前显示的索引路径来更新当前显示的内容,将这些索引路径与您的倒计时对象匹配数组,然后更改所有不同标签的文本。这意味着您的视图控制器中只有一个NSTimer实例负责驱动更新。

  4. 还有很多其他可能的方法来构建这个,但我认为试图管理许多计时器实例会导致一些白发。

答案 1 :(得分:1)

传递给NSTimer scheduledTimerWithTimeInterval(_:target:selector:userInfo:repeats:)的选择器会收到NSTimer个对象,而不是NSIndexPath

也就是说,您的update(_:)方法应定义为

func update(timer: NSTimer) {
    cellIndex = timer.userInfo as! NSIndexPath
    ...
}

有关详细信息,请参阅method's documentation

答案 2 :(得分:0)

更简单的方法是继续运行你的nstimer az isvand调用倒计时方法并在最后重新加载你的UITableView。保持值在重新加载之前每次都显示在NSArray中,并将其作为对象传递给UITableView。