=== 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>
这里奇怪的是,前两天(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开发的新手,所以一些帮助真的很值得! 谢谢!