当 collectionview 刷新时,CollectionView 单元格的计时器会混淆

Posted

技术标签:

【中文标题】当 collectionview 刷新时,CollectionView 单元格的计时器会混淆【英文标题】:CollectionView cell's timers get mixed up when collectionview refreshes 【发布时间】:2019-01-01 22:45:18 【问题描述】:

我有一个 collectionView,它在每个单元格中都包含计时器。但是,当应用程序启动时,所有计时器都可以正常工作,但是,当我刷新集合视图时,所有计时器都会混淆并且到处都是。我很确定这与以前的计时器没有关闭有关。

集合视图代码:

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "contestsCell", for: indexPath) as! ContestsCollectionViewCell
    cell.nameLabel.text = listingArray[indexPath.row].name


    let arr = [listingArray[indexPath.row].expiryDate, cell.expiryDateLabel] as [AnyObject]

    timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateCounting), userInfo: arr, repeats: true)

    return cell

定时器功能代码:

@objc func updateCounting(timer:Timer)
    // here we set the current date

    var dateArray: [AnyObject] = timer.userInfo as! [AnyObject]

    let itemDate = dateArray[0] as! String
    var dateList = itemDate.components(separatedBy: "-")

    let dateLabel = dateArray[1] as! UILabel

    let date = NSDate()
    let calendar = Calendar.current

    let components = calendar.dateComponents([.hour, .minute, .month, .year, .day, .second], from: date as Date)

    let currentDate = calendar.date(from: components)

    let userCalendar = Calendar.current

    // here we set the due date. When the timer is supposed to finish
    let competitionDate = NSDateComponents()
    competitionDate.year = Int(dateList[0])!
    competitionDate.month = Int(dateList[1])!
    competitionDate.day = Int(dateList[2])!
    competitionDate.hour = 00
    competitionDate.minute = 00
    competitionDate.second = 00
    let competitionDay = userCalendar.date(from: competitionDate as DateComponents)!

    //here we change the seconds to hours,minutes and days
    let CompetitionDayDifference = calendar.dateComponents([.day, .hour, .minute, .second], from: currentDate!, to: competitionDay)


    //finally, here we set the variable to our remaining time
    let daysLeft = CompetitionDayDifference.day
    let hoursLeft = CompetitionDayDifference.hour
    let minutesLeft = CompetitionDayDifference.minute
    let secondsLeft = CompetitionDayDifference.second

    if competitionDay > currentDate as! Date 
        //Set countdown label text
        dateLabel.text = "\(daysLeft ?? 0): \(hoursLeft ?? 0): \(minutesLeft ?? 0): \(secondsLeft ?? 0)"
    


刷新collectionView的代码

@objc func loadData() 

    retrieveContests()
    listingArray.removeAll()
    self.refresher.endRefreshing()

【问题讨论】:

【参考方案1】:

我认为您的问题与您将单元格出列这一事实有关。因为这背后的原理是 ios 会重用现有的单元格对象,这可能会导致一些问题。

例如在您使用 countdown1 和计时器创建 cell1 的方法中,与 cell2 和 countdown2 (+计时器)相同。一旦你重新加载你的collectionView cell1 和cell2 将被重用,但现在cell1 将有一个不同的索引路径,因此用于countdown2,并且还会创建一个新的计时器。

这可能会导致您的计时器在过程中混淆的问题,据我在您的代码中看到的,您也永远不会停止任何计时器,所以我会说您的假设是正确的。每次重新加载集合视图时,您都会创建更多计时器。

我解决这个问题的建议是:在每个包含用于计算倒计时的日期对象的单元格上创建一个属性。然后只需使用一个计时器来通知所有单元格自行更新其内容。也许您可以为此使用 NotificationCenter。 这种(或类似的方法)应该可以帮助您并避免维护所有这些计时器的整个问题。

【讨论】:

您可以查看my answer 以获得类似的tableview 方法;将其调整为集合视图应该非常简单 @Paulw11 谢谢,我懒得实际创建相同的代码;)这是一种方法。但是对于这种情况,我仍然会寻求一个只有一个计时器的解决方案。我的理由是:因为(据我了解)我们正在处理某些事件(“竞赛”)的倒计时,我认为它们应该以 1 秒的间隔同时更改(多个计时器不能保证)并且不是单独停止/启动。因此,我们不需要为每个单元管理计时器的麻烦 我的代码有一个Timer;视图控制器中的属性timertimers 数组包含 TimerModel 的实例,用作单元格的数据模型。 哦,对不起。我的错!应该仔细看看。在这种情况下:很好的解决方案!

以上是关于当 collectionview 刷新时,CollectionView 单元格的计时器会混淆的主要内容,如果未能解决你的问题,请参考以下文章

带有 TableView 和 CollectionView 的 UiView 不会随机刷新

如何在 CollectionView iOS 中停止自动重新加载和刷新图像

按照用户方向旋转collectionView

CollectionView 标题在滚动时停止刷新/重新加载数据

检索 UserDefaults 后在 viewdidload 上刷新 collectionView

平移和滚动放大的collectionView xcode