In my project I have multiple types of UITableview
cell each containing UICollectionview
.
Initially I loaded 2 tableViewcell
in 2 sections of UITableview
. At first it loads fine without any problem. If I scroll the first section it scrolls nice but when I try to scroll the second section it gives me the following error:
the cell returned from -collectionView:cellForItemAtIndexPath: does not have a reuseIdentifier - cells must be retrieved by calling -dequeueReusableCellWithReuseIdentifier:forIndexPath:
I have the following code to set up the process:
class Home: UITableViewDelegate, UITableViewDataSource, UICollectionViewDelegate, UICollectionViewDataSource{
override func viewDidLoad() {
self.tableView.register(SliderViewCell.nib, forCellReuseIdentifier: SliderViewCell.identifier)
self.tableView.register(GridViewCell.nib, forCellReuseIdentifier: GridViewCell.identifier)
self.tableView.estimatedRowHeight = 80
self.tableView.rowHeight = UITableViewAutomaticDimension
}
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let viewObj = self.viewObject[indexPath.section]
if viewObj.itemType! == HomeViewItemType.Slider.rawValue{
if let sliderCell = cell as? SliderViewCell {
sliderCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)
}
}
else if viewObj.itemType! == HomeViewItemType.Grid.rawValue{
if let gridCell = cell as? GridViewCell {
gridCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if self.viewObject.count>0{
let viewObj = self.viewObject[indexPath.section]
if viewObj.itemType! == HomeViewItemType.Slider.rawValue{
let cell:SliderViewCell = tableView.dequeueReusableCell(withIdentifier: SliderViewCell.identifier, for: indexPath) as! SliderViewCell
cell.contentView.tag = indexPath.section
return cell
}
else if viewObj.itemType! == HomeViewItemType.Grid.rawValue{
let cell:GridViewCell = tableView.dequeueReusableCell(withIdentifier: GridViewCell.identifier, for: indexPath) as! GridViewCell
cell.contentView.tag = indexPath.section
return cell
}
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("selected")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.viewObject[section].viewData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if viewObj.itemType! == HomeViewItemType.Slider.rawValue{
if let cell:SliderCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: SliderCollectionViewCell.identifier, for: indexPath) as? SliderCollectionViewCell{
if viewObj.viewData.count>0{
if let imageURL = URL(string: viewData.imageLink!){
cell.icon.sd_setImage(with: imageURL, completed: nil)
}
}
return cell
}
}
else if viewObj.itemType! == HomeViewItemType.Grid.rawValue{
if let cell:GridCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: GridCollectionViewCell.identifier, for: indexPath) as? GridCollectionViewCell{
if viewObj.viewData.count>0{
if let imageURL = URL(string: viewData.icon!){
cell.icon.sd_setImage(with: imageURL, completed: nil)
}
}
return cell
}
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("tapped")
}
}
class SliderViewCell: UITableViewCell {
@IBOutlet weak var collectionView: UICollectionView!
static var nib:UINib {
return UINib(nibName: identifier, bundle: nil)
}
static var identifier:String {
return String(describing: SliderViewCell.self)
}
var collectionViewCellWidth : CGFloat = 15.0
var collectionViewCellHeight : CGFloat = 150.0
var cellSpaceWidth : CGFloat = 8.0
override func awakeFromNib() {
super.awakeFromNib()
self.configureCollectionViewCell(nibFile: SliderCollectionViewCell.nib, identifier: SliderCollectionViewCell.identifier, width: collectionView.frame.size.width, height: 80, topInset: 0, leftInset: 0, bottomInset: 0, rightInset: 0, cellSpace: cellSpaceWidth, interimSpace: 0.0, scrollInDirection: .horizontal)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
class GridViewCell: UITableViewCell {
@IBOutlet weak var collectionView: UICollectionView!
static var nib:UINib {
return UINib(nibName: identifier, bundle: nil)
}
static var identifier:String {
return String(describing: GridViewCell.self)
}
var collectionViewCellWidth : CGFloat = 15.0
var collectionViewCellHeight : CGFloat = 150.0
var cellSpaceWidth : CGFloat = 8.0
override func awakeFromNib() {
super.awakeFromNib()
self.configureCollectionViewCell(nibFile: GridCollectionViewCell.nib, identifier: GridCollectionViewCell.identifier, width: collectionView.frame.size.width, height: 80, topInset: 0, leftInset: 0, bottomInset: 0, rightInset: 0, cellSpace: cellSpaceWidth, interimSpace: 0.0, scrollInDirection: .horizontal)
}
func configureCollectionViewCell(nibFile:UINib, identifier:String,width:CGFloat,height:CGFloat, topInset:CGFloat,leftInset:CGFloat,bottomInset:CGFloat,rightInset:CGFloat, cellSpace:CGFloat, interimSpace:CGFloat,scrollInDirection:UICollectionViewScrollDirection){
let nib = nibFile
collectionView.register(nib, forCellWithReuseIdentifier: identifier)
let cellWidth : CGFloat = width//collectionView.frame.size.width
let cellheight : CGFloat = height//collectionViewCellHeight
let cellSize = CGSize(width: cellWidth , height:cellheight)
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = scrollInDirection
layout.itemSize = cellSize
layout.sectionInset = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
layout.minimumLineSpacing = cellSpace
layout.minimumInteritemSpacing = interimSpace
collectionView.setCollectionViewLayout(layout, animated: true)
collectionView.reloadData()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension GridViewCell{
func setCollectionViewDataSourceDelegate<D: UICollectionViewDataSource & UICollectionViewDelegate>(_ dataSourceDelegate: D, forRow row:Int){
collectionView.delegate = dataSourceDelegate
collectionView.dataSource = dataSourceDelegate
collectionView.reloadData()
}
}
I think the GridViewCell
which loads in the 2nd section of UITableview causing the problem. But I've already added dequeueReusableCellWithReuseIdentifier
in the collectionView:cellForItemAtIndexPath:
method. So I'm clueless what's causing the error.
Any help would be greatly appreciated.
The collection view maintains a queue or list of view objects that the data source has marked for reuse. Instead of creating new views explicitly in your code, you always dequeue views. There are two methods for dequeueing views.
From apple's documentation, UICollectionView is: An object that manages an ordered collection of data items and presents them using customizable layouts. The name and definition makes it clear, it is a way to display a Collection of UI Views in our app.
Here are two ways that you can use to handle your cells instead of if else then UICollectionViewCell()
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath)
if let gridCell = cell as? GridCollectionViewCell {
// TODO: configure cell
}
return cell
Another way is to
guard let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath)
as? GridCollectionViewCell else {
//Handle error first so you can return a perfect cell if there is no error
}
Remove UICollectionViewCell() it's causing the issue because there is no reuse identifier for that cell.
i resolve this problem by i missed to return cell in one collection view. i am using multiple collection view and i missed to return cell in " let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CropName", for: indexPath) as! CropNameCollectionViewCell return cell
see somewhere you missed to return cell
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With