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

IOS: Updating Labels in a UITableViewCell using an NSTimer

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

.
.
.
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)")
}

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

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFTimer row]: unrecognized selector sent to instance

这是无效的代码。

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) { ...

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

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

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

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

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

我会推荐一种不同的方法来构建您的应用程序。

UITableView 将使用 dequeueReusableCellWithIdentifier 方法 "recycle" 其单元格。因此,如果用户要使用您的应用程序创建 100 个倒计时,但屏幕上最多只能显示 4 个单元格,当用户滚动时,这四个单元格将排入 table 视图的单元格缓存中,然后由您的数据源代码出列。这样做是为了提高性能,以便 table 视图可以平滑滚动。您可以在 Apple 的 Table View Programming Guide.

中阅读有关此行为的更多信息

如果是我...

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

  2. 我将使用这些对象的数组作为 table 视图表示的数据。

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

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