6
\$\begingroup\$

I am making countdown app with multiple records, so I am using UITableView to show that records and countdown dates. What I do is just take one timer and reload cells on every second. Is this a best approach to reload visible cells on every second or is there another better approach there?

updateCellContentsTimer = Timer.scheduledTimer(timeInterval: 1,
            target: self,
          selector: #selector(ViewController.updateCells),
          userInfo: nil, repeats: true)



// MARK: Custom Functions

func updateCells() {
    let indexPathsArray = tableView.indexPathsForVisibleRows
    for indexPath in indexPathsArray! {
        let cell = tableView.cellForRow(at: indexPath) as! CountdownTableViewCell

        cell.timeLeftLabel.text = progress + "hours:minutes:seconds"
    }
}
\$\endgroup\$
5
  • \$\begingroup\$ Instead of reloading every cell on timer event you can use the notification mechanism of Cocoa. \$\endgroup\$
    – Shial
    Apr 14, 2017 at 1:28
  • 1
    \$\begingroup\$ @Shial, since it's a countdown, every visible cell needs to change every second. Doing that indirectly through notifications only adds complexity without avoiding the cell updates. The OP already limits the updates to visible cells so the process is optimal. \$\endgroup\$
    – Alain T.
    Apr 19, 2017 at 13:22
  • \$\begingroup\$ @AlainT. so this is the right way to update time in every cell .. right?? \$\endgroup\$ Apr 21, 2017 at 4:44
  • 2
    \$\begingroup\$ Yes. What makes it right is that you use indexPathsForVisibleRows. This is the smallest number of cell updates that you can do for your countdown. Having only one timer to manage all the countdowns is also the optimal way to do it. \$\endgroup\$
    – Alain T.
    Apr 21, 2017 at 4:54
  • \$\begingroup\$ @AlainT. thanks buddy ... thanks for your suggestion .. really appreciate :) \$\endgroup\$ Apr 21, 2017 at 5:00

2 Answers 2

3
\$\begingroup\$

to avoid DRY i would put this line (i think it is in your code only a sample logic) inside the cell. in this case you have the logic for calculating the remaining time inside the cell and not outside somewhere. and you can use always the same function to update the progress.

cell.timeLeftLabel.text = progress + "hours:minutes:seconds"

should be become

cell.updateProgress()
\$\endgroup\$
0
\$\begingroup\$

Swift 5

There is another way to update time on label in cell by CADisplayLink, CADisplayLink is part of CoreAnimation.

It helps for smooth UI update with animation in 1 second interval, by this way you no need to add timer and time interval in cell.

And You no need to add for loop of visibleCells, to just update the label in 1 second time interval.

override func awakeFromNib() {
        super.awakeFromNib()
        let displayLink = CADisplayLink(target: self,selector: #selector(updateDate))
        displayLink.add(to: RunLoop.main, forMode: .common)
     }
    
    @objc func updateDate() {
       if let date = objServiceRequest?.dateCreated?.getDateFromString() {
          lblTime.text = "\(date.getElapsedInterval())".uppercased()
       }
    }

Note: You can check frame update rate by this calculation:

 let actualFramesPerSecond = 1 / (displaylink.targetTimestamp - displaylink.timestamp)

Reference: https://developer.apple.com/documentation/quartzcore/cadisplaylink

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Welcome to Code Review! Could you please explain why this is better or why you would code it this way versus what the OP coded? This answer is very close to what we call a "Code Only" answer, meaning that it isn't a "Review" of the code in the OP. our site is a little different than others. Please check out our how to answer page for more information on how to write a good Review (Answer) on Code Review \$\endgroup\$
    – Malachi
    Apr 9, 2021 at 19:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.