ios UIProgressBar忽略代码并在视图从后台返回后停留在随机值上

vdgimpew  于 2023-08-08  发布在  iOS
关注(0)|答案(1)|浏览(89)

bounty将在3天后过期。回答此问题可获得+50声望奖励。David希望引起更多的注意这个问题:感谢您阅读我的问题。我提供一些代表的人谁可以帮助我解决这个问题。

我在UITableViewCell中有一个UIProgressBar,它根据倒数计时器每秒更新一次,该计时器也在单元格的对象内部运行。在大多数情况下,它工作得很好,直到应用程序被背景化或另一个模态视图覆盖它--不知何故,普通视图不会触发这一点。
一旦应用程序从这种状态返回,进度条就会停止监听计时器,并停留在应用程序中其他任何地方都没有引用的同一个随机值(大约10%)上。奇怪的是,当我在计时器中修改进度条后打印它的当前进度时,它正确地返回,尽管UI不尊重它。
以下是本期节目的录音:https://imgur.com/a/oZ9AGUh
下面是相关代码:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    DispatchQueue.main.async {
        (cell as! CountdownTable).timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { timer in
            let nowToEvent = (cell as! CountdownTable).dateTarget - Date()
            let thenToEvent = (cell as! CountdownTable).dateTarget - (cell as! CountdownTable).dateWhenSet
            
            let elapsed = thenToEvent - nowToEvent
            (cell as! CountdownTable).countdownBar.setProgress(Float(elapsed / thenToEvent), animated: true)
            (cell as! CountdownTable).countdownDate.text = (cell as! CountdownTable).dateTarget.timeFromDate(from: Date())
        })
    }
}

func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    (cell as! CountdownTable).timer.invalidate()
}

字符串

7qhs6swi

7qhs6swi1#

这段代码通过对整个表格视图使用一个Timer而不是对每个单元格使用一个计时器,解决了在应用程序后台化或显示模态视图后进度条不更新的问题。
解决方案要点如下:

  1. Timer示例现在是管理表视图的UIViewController的一部分,而不是单独的UITableViewCell的一部分。当视图控制器的视图出现(viewDidAppear(_:))时,此计时器启动;当视图消失(viewWillDisappear(_:))时,此计时器失效。
    1.计时器每0.1秒触发一次,并调用updateVisibleCells函数。选择0.1秒的间隔是为了提供更平滑的UI更新。您可以根据需要和性能考虑因素调整此值。
  2. updateVisibleCells函数会反覆查看表格检视中所有目前可见的储存格(透过呼叫tableView.indexPathsForVisibleRows取得)。它会计算经过的时间,并更新每个可见储存格的进度列进度。
    1.此方法可确保当应用程序从后台返回或模式视图被关闭时,进度条继续更新,因为计时器会在视图控制器可见的时间内继续运行,而不管单元格级别的任何更改。
    1.通过不在每个表单元格中使用计时器,这种方法还提高了性能和电池效率,因为不管可见单元格的数量如何,都只使用单个计时器。当表格视图有许多单元格时,这一点尤其有用。
    下面是代码的重构版本,它考虑了@Rob和@Paulw11讨论的建议。请注意,此代码假定存在一个存储dateWhenSetdateTarget值的模型,以及一个计算timeFromDate(from:)的方法。
class CountdownTable: UITableViewCell {
    var timer: Timer?
    var dateWhenSet: Date?
    var dateTarget: Date?
    var countdownBar: UIProgressView!
    var countdownDate: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        // setup cell
    }
}

class YourViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    var timer: Timer?
    var tableView: UITableView!

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateVisibleCells), userInfo: nil, repeats: true)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        timer?.invalidate()
    }

    @objc func updateVisibleCells() {
        guard let visibleRows = tableView.indexPathsForVisibleRows else { return }
        for indexPath in visibleRows {
            guard let cell = tableView.cellForRow(at: indexPath) as? CountdownTable else { continue }
            let nowToEvent = cell.dateTarget! - Date()
            let thenToEvent = cell.dateTarget! - cell.dateWhenSet!
            let elapsed = thenToEvent - nowToEvent
            cell.countdownBar.setProgress(Float(elapsed / thenToEvent), animated: true)
            cell.countdownDate.text = cell.dateTarget?.timeFromDate(from: Date())
        }
    }

}

字符串
此代码在viewDidAppear(_:)中设置一个计时器,该计时器每0.1秒触发一次,以更新当前可见单元格的进度条。计时器在viewWillDisappear(_:)中无效,以确保当视图控制器不再可见时停止。这是一种比为每个单元创建和管理单独的计时器更有效的方法。
此解决方案假定UITableViewCell子类具有属性countdownBarcountdownDatedateTargetdateWhenSet。请确保这些属性存在并且已正确配置。
此解决方案可在原始问题中概述的所有情况下保持进度条和倒计时器的更新。通过将计时器移动到视图控制器并仅在可见单元格上迭代,它还提供了更高效、更平滑的UI更新。

相关问题