简体   繁体   English

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

[英]How to update UITableViewCells using NSTimer and NSNotificationCentre in Swift

NOTE: Asking for answers in Swift please. 注意:请在Swift中寻求答案。

What I'm trying to do: 我正在尝试做什么:

  • Have tableview cells update every 1 second and display a real-time countdown. 让tableview单元每1秒更新一次,并显示实时倒计时。

How I'm doing it currently: 我目前是怎么做的:

  • I have a tableview with cells that contain a label. 我有一个包含标签的单元格的tableview。

  • When the cells are generated, they call a function that calculates the time between today and a stored target date, and it displays the countdown time remaining in the label. 生成单元格后,它们会调用一个函数来计算今天和存储的目标日期之间的时间,并显示标签中剩余的倒计时时间。

  • To get the cells to update the label every second, I use an NSTimer that reloads the tableview every second. 为了让单元格每秒更新标签,我使用NSTimer每秒重新加载tableview。

  • PROBLEM: The countdown works, but when I try to do a Swipe-to-Delete action, because the NSTimer reloads the tableview, it resets the swiped cell so that it is no longer swiped and of course this is not acceptable for end users. 问题:倒计时有效,但是当我尝试执行“刷卡到删除”操作时,因为NSTimer重新加载了表格视图,它会重置刷过的单元格以便不再刷卡,当然这对最终用户来说是不可接受的。

What I'm trying / Potential Solutions 我正在尝试/潜在的解决方案

  • I heard that a better way to do this is to use NSNotificationCenter that is triggered by NSTimer and add listeners to each cell. 我听说更好的方法是使用由NSTimer触发的NSNotificationCenter并为每个单元添加侦听器。 Every 1 second a "broadcast" is sent from the NSNotificationCenter , the cell will receive the "broadcast" and will update the label. 每隔1秒从NSNotificationCenter发送一次“广播”,该小区将收到“广播”并将更新标签。

  • I tried adding a listener to each cell in the part of the code where it generates a new cell: 我尝试在代码中生成新单元格的每个单元格中添加一个侦听器:

     // 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 } } 
  • but the observer's selector only seems to be able to target functions at the view controller level, not in the cell. 但观察者的选择器似乎只能在视图控制器级别而不是在单元格中定位功能。 (I can't get "updateCountdownLabel" to fire from within the cell. When I create a function of the same name at view controller level, the function can be called) (我无法从单元格中触发“updateCountdownLabel”。当我在视图控制器级别创建同名函数时,可以调用该函数)

Questions 问题

  • So my question is: Is this is the right approach? 所以我的问题是:这是正确的方法吗?
  • If yes, how can I get the listener to fire a function at the cell level? 如果是,我如何让监听器在单元级别触发函数?
  • If no, then what is the best way to achieve this real-time countdown without interrupting Swipe on Cell actions? 如果不是,那么在不中断Swipe on Cell操作的情况下实现此实时倒计时的最佳方法是什么?

Thanks in advance for your help! 在此先感谢您的帮助!

It might be a solution not reloading cells at all. 它可能是一种根本不重新加载细胞的解决方案。 Just make the cells listen to an update notification and change their label accordingly. 只需让单元格听取更新通知并相应地更改其标签。 I assume you subclass UITableViewCell and give the cell a storedDate property. 我假设你是UITableViewCell子类,并给单元格一个storedDate属性。 You will set that property when preparing the cell. 您将在准备单元格时设置该属性。

The timer will just fire the notification. 计时器只会触发通知。

Remember to unregister the cell from notification center in dealloc 请记住在dealloc从通知中心取消注册单元格

Here is a quick an dirty example. 这是一个简单的例子。

The View Controller containing your TableView: 包含TableView的View Controller:

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
    }

}

The custom cell subclass: 自定义单元子类:

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

}

I'm pretty sure this example doesn't adhere to your app's logic. 我很确定这个例子不符合你应用的逻辑。 Just showing how things are glowed together. 只是展示事物是如何一起发光的

As Ian MacDonald has suggested you should avoid reloading the cell when the timer ticks, if you are swiping. 正如Ian MacDonald建议你应该避免在计时器滴答时重新加载单元格,如果你正在滑动。 Also drop the NSNotification, as It and timer are essentially doing the samething 同时放弃NSNotification,因为它和计时器本质上是做同样的事情

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM