如何在Swift中使用NSTimer和NSNotificationCentre更新UITableViewCells

时间:2015-02-16 04:26:46

标签: ios uitableview swift nstimer nsnotificationcenter

注意:请在 Swift 中寻求答案。

我想做的事情:

  • 每1秒更新一次tableview单元格并显示实时 倒计时。

我目前的表现如何:

  • 我有一个包含标签的单元格的tableview。

  • 生成单元格时,它们会调用一个函数来计算今天和存储的目标日期之间的时间,并显示标签中剩余的倒计时时间。

  • 为了让细胞每秒更新标签,我 使用NSTimer每秒重新加载tableview。

  • 问题:倒计时有效,但当我尝试执行“刷卡到删除”操作时,因为NSTimer重新加载了表格视图,它会重置 刷过单元格以便不再刷卡,当然这对最终用户来说是不可接受的。

我尝试/潜在解决方案

  • 我听说更好的方法是使用由NSNotificationCenter触发的NSTimer并为每个单元格添加侦听器。每1秒一次"广播"从NSNotificationCenter发送,小区将收到"广播"并将更新标签。

  • 我尝试在代码中生成新单元格的部分中的每个单元格中添加一个侦听器:

    // Generate the cells
    
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    
    var cell = tableView.dequeueReusableCellWithIdentifier("Tablecell", forIndexPath: indexPath) as UITableViewCell
    let countdownEntry = fetchedResultController.objectAtIndexPath(indexPath) as CountdownEntry
    
    // MARK: addObserver to "listen" for broadcasts
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "updateCountdownLabel", name: mySpecialNotificationKey, object: nil)
    
    func updateCountdownLabel() {
        println("broadcast received in cell")
        if let actualLabelCountdown = labelCountdown {
            // calculate time between stored date to today's date
            var countdownValue = CountdownEngine.timeBetweenDatesRealTime(countdownEntry.date)
            actualLabelCountdown.text = countdownValue
        }
    }
    
  • 但观察者的选择器似乎只能在视图控制器级别而不是在单元格中定位功能。 (我无法获取" updateCountdownLabel"从单元格中触发。当我在视图控制器级别创建同名函数时,可以调用该函数)

问题

  • 所以我的问题是:这是正确的做法吗?
  • 如果是,我如何让监听器在单元级别触发函数?
  • 如果不是,那么在不中断Swipe on Cell操作的情况下实现此实时倒计时的最佳方法是什么?

提前感谢您的帮助!

2 个答案:

答案 0 :(得分:14)

这可能是一种根本不重新加载细胞的解决方案。只需让单元格听取更新通知并相应地更改其标签。 我假设你是子类UITableViewCell并给单元格一个storedDate属性。您将在准备单元格时设置该属性。

计时器只会触发通知。

请务必在dealloc

中的通知中心取消注册该单元格

这是一个简单的例子。

包含TableView的视图控制器:

class ViewController: UIViewController, UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!

    var timer: NSTimer!


    //MARK: UI Updates

    func fireCellsUpdate() {
        let notification = NSNotification(name: "CustomCellUpdate", object: nil)
        NSNotificationCenter.defaultCenter().postNotification(notification)
    }

    //MARK: UITableView Data Source

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cellIdentifier = "CustomCell"
        let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as! CustomTableViewCell
        cell.timeInterval = 20
        return cell
    }

    //MARK: View Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.timer = NSTimer(timeInterval: 1.0, target: self, selector: Selector("fireCellsUpdate"), userInfo: nil, repeats: true)
        NSRunLoop.currentRunLoop().addTimer(self.timer, forMode: NSRunLoopCommonModes)
    }


    deinit {
        self.timer?.invalidate()
        self.timer = nil
    }

}

自定义单元格子类:

class CustomTableViewCell: UITableViewCell {

    @IBOutlet weak var label: UILabel!

    var timeInterval: NSTimeInterval = 0 {
        didSet {
            self.label.text = "\(timeInterval)"
        }
    }

    //MARK: UI Updates

    func updateUI() {
        if self.timeInterval > 0 {
            --self.timeInterval
        }
    }

    //MARK: Lifecycle

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code

        let notificationCenter = NSNotificationCenter.defaultCenter()
        notificationCenter.addObserver(self, selector: Selector("updateUI"), name: "CustomCellUpdate", object: nil)
    }

    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

}

我很确定此示例不符合您应用的逻辑。只是展示一起如何发光

答案 1 :(得分:1)

正如Ian MacDonald所建议的那样,如果你正在滑动,你应该避免在计时器滴答时重新加载细胞。同时删除NSNotification,因为它和计时器本质上是做同样的事情