重用单元格

时间:2018-02-18 18:37:37

标签: ios swift uitableview uicollectionview reuseidentifier

=== EDIT ===

确定!最后我想我已经成功了。当我阅读本文(http://matteomanferdini.com/the-correct-way-to-display-lists-in-ios-and-what-many-developers-do-wrong/#reuse)时,我想应用最佳实践,因此我进行了一些重构并为我的数据源创建了一个新类。通过这样做,我想我已经找到了为什么我会遇到这个奇怪的问题。现在,对于我的TableView单元格( AgendaTableViewCell ),我删除了events属性,并改为使用day属性。在这里我的新班级

//
//  AgendaTableViewCell.swift
//  fnfa
//
//  Created by JBARA Omar on 15/02/2018.
//  Copyright © 2018 JBARA Omar. All rights reserved.
//

import UIKit

class AgendaTableViewCell: UITableViewCell {

    @IBOutlet weak var eventsCollectionView: UICollectionView!

    var eventsDataSource: EventsDataSource?
    var day: Date? {
        didSet{
            setup()
        }
    }
    let dateFormatter = DateFormatter()

    private func setup() {
        self.eventsDataSource = EventsDataSource(events: DataMapper.instance.events.findBy(date: day!)!)
        print("setup row")
        print(day)
        print(self.eventsDataSource?.events)
        dateFormatter.setLocalizedDateFormatFromTemplate("d")
        eventsCollectionView.dataSource = eventsDataSource
        eventsCollectionView.reloadData()
        eventsCollectionView.register(UINib(nibName: "EventCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: String(describing: EventCollectionViewCell.self))
    }

}

我想我第一次没有得到过时的值,因为现在,每次重用一个单元格时,它都设置day属性,因此调用setup方法。现在我确定它会使用特定日期的正确事件设置数据。我认为之前发生的事情是它使用了另一个重用单元格中的旧events属性。我不知道这是否是实现这一目标的好方法(每次重复使用单元格时设置数据源这一事实似乎不可行,但由于我依赖于day属性,我可能不会这样做,但实际上它正在发挥作用!

===初始问题===

我不知道这是一个错误还是我太愚蠢,但最近这件事让我发疯了。让我解释一下发生了什么。

首先,我在json中有一个事件列表,我正在加载和解析。它工作得很好。

在一个视图中,我显示了几天的事件。它由TableView组成。在这个TableView中,我使用自定义类单元格制作了xib文件,在我的代码中我正确地注册了它们(使用tableView.register(UINib(nibName: "AgendaTableViewCell", bundle: nil), forCellReuseIdentifier: "dayRow")

然后这是棘手的部分。在我的表格视图中,我每天都会显示一个标题,因此为每个部分定义一个部分,在每个部分中,我只有一行。

在这一行中,我正在显示一个CollectionView,我还在一个带有自定义类的xib文件中创建了一个CollectionViewCell模板。它正确地从我的json中获取数据,但我有一个非常讨厌的问题。

这是第一个帮助您了解发生了什么的gif,以及我的 AgendaViewController (具有TableView的主视图), AgendaTableViewCell 的代码,它是我的TableView中的单元格,还负责管理单元格中的CollectionView,以及 EventCollectionViewCell ,它代表集合视图的单个单元格(这是显示有关事件信息的单元格)。 / p>

show gif

这里奇怪的是,前两天(Mercredi 4和Jeudi 5),它按预期工作,但对于Vendredi 6来说,它变得非常奇怪。问题不在于我提取的数据,因为我在AgendaTableViewCell中验证了我的events: [Event]?并且它具有正确的事件。

我认为问题实际上是在出列/重用细胞。因为当我去第二个单元格,然后回到第一个单元格时,它按预期工作,我不再有问题。我真的不知道该怎么做,我已经尝试过prepareForReuse,但是如果我理解正确的话,它与视觉内容有关,比如重置图像以防止来自另一个单元的图像被重用。但在这里,文本内容确实是错误的,只有这一点。我真的不明白这里发生了什么。另外,如果我在我的days arrray上只用了3天就可以正常工作,那真的很奇怪。但是当数组长于3时,就会出现错误。这是奇怪的部分。我注意到它似乎遵循一种奇怪的模式。我测试了15天,在我的馆藏视图中,它看起来像是第一个单元格,它在重复使用之前是从第4天,第5天和第8天开始。它一直在继续。

这是我的档案:

AgendaViewController

//
//  AgendaViewController.swift
//  fnfa
//
//  Created by JBARA Omar on 15/02/2018.
//  Copyright © 2018 JBARA Omar. All rights reserved.
//

import UIKit

class AgendaViewController: UITableViewController {


    private let reuseIdentifier = "dayRow"

    private var days = [
        Date(timeIntervalSince1970: 1522836000), // 4 Avril 2018, 12:00
        Date(timeIntervalSince1970: 1522922400), // 5 Avril 2018, 12:00
        Date(timeIntervalSince1970: 1523008800), // 6 Avril 2018, 12:00
        Date(timeIntervalSince1970: 1523095200), // 7 Avril 2018, 12:00
        Date(timeIntervalSince1970: 1523181600)  // 8 Avril 2018, 12:00
    ]
    private let dateFormatter = DateFormatter()
    private let locale = Locale(identifier: "fr_FR")

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.allowsSelection = false
        dateFormatter.locale = locale
        tableView.register(UINib(nibName: "AgendaTableViewCell", bundle: nil), forCellReuseIdentifier: reuseIdentifier)
        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let row = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) as! AgendaTableViewCell
        row.events = DataMapper.instance.events.findBy(date: days[indexPath.section])
        return row
    }


    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return days.count
    }

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

    override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let view = super.tableView(tableView, viewForHeaderInSection: section)
        view?.backgroundColor = #colorLiteral(red:0.1175380871, green:0.1734368503, blue:0.310670346, alpha:1)

        return view
    }

    override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 50
    }

    override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        if (view is UITableViewHeaderFooterView) {
            let header = view as! UITableViewHeaderFooterView
            dateFormatter.setLocalizedDateFormatFromTemplate("EEEE d")
            header.textLabel?.text = dateFormatter.string(from: days[section]).capitalized(with: locale)
            header.textLabel?.textAlignment = .center
            header.textLabel?.textColor = #colorLiteral(red:1.0, green:1.0, blue:1.0, alpha:1.0)
        }
    }

}

EventCollectionViewCell

//
//  XIBEventCollectionViewCell.swift
//  fnfa
//
//  Created by Jbara Omar on 18/02/2018.
//  Copyright © 2018 JBARA Omar. All rights reserved.
//

import UIKit

class EventCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var eventImage: UIImageView!
    @IBOutlet weak var labelTitle: UILabel!

    var event: Event? {
        didSet{
            eventImage.image = event?.getUIImage()
            labelTitle.text = event?.name
        }
    }


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



}

AgendaTableViewCell

//
//  AgendaTableViewCell.swift
//  fnfa
//
//  Created by JBARA Omar on 15/02/2018.
//  Copyright © 2018 JBARA Omar. All rights reserved.
//

import UIKit

class AgendaTableViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {

    @IBOutlet weak var eventsCollectionView: UICollectionView!

    let dateFormatter = DateFormatter()
    var identifier = "events"
    var events: [Event]?

    override func awakeFromNib() {
        super.awakeFromNib()
        dateFormatter.setLocalizedDateFormatFromTemplate("d")
        eventsCollectionView.delegate = self as UICollectionViewDelegate
        eventsCollectionView.dataSource = self as UICollectionViewDataSource
        eventsCollectionView.register(UINib(nibName: "EventCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: identifier)
    }


    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return (events?.count)!
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = eventsCollectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! EventCollectionViewCell
        cell.event = events?[indexPath.item]
        return cell
    }


    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

DataMapper 只是我从json获取数据的一个类,这里​​放置代码并不重要,因为它只在内部使用JSONDecoder。

我是iOS开发的新手,所以一些帮助真的很值得! 谢谢!

0 个答案:

没有答案