I've got a UITableView
where each prototype cell has a UICollectionView
in it. This collection view is supposed to be a grid of images. I'm very new to Swift, and have googled for hours (and read plenty of StackOverflow articles), and cannot seem to find the correct answer to this question.
How come collectionView cellForItemAt is not being called?
I see that my collectionView numberOfItemsInSection
method, and collectionView sizeForItemAt
methods get called. I've made sure to assign my TableViewCell
as the delegate and dataSource of the collectionView. I did this both in the Interface Builder with outlets, and again in my custom TableViewCell's awakeFromNib
method with
cardImagesCollection.delegate = self
cardImagesCollection.dataSource = self
No matter what I do, I cannot seem to get this to call it. I made sure that I had good constraints set up because that burned me once on the tableViewCells.
For the life of me, I cannot get it to load up the collectionView.
Any help would be greatly appreciated.
Specifically, I'm using Xcode 9.4.1 and Swift 4.1.
Thanks
Edit - Adding sample code
HomeViewController: UIViewController
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LatestCardCell", for: indexPath) as! LatestCardsTableViewCell
cell.backgroundColor = UIColor.clear
cell.card = cards[indexPath.row]
return cell
}
LatestCardsTableViewCell: UITableViewCell
@IBOutlet weak var cardImagesCollection: UICollectionView!
var card: Card! {
didSet {
titleLabel.attributedText = FontUtil.attributedCardTitleText(string: card.title)
descriptionLabel.attributedText = FontUtil.attributedCardDescriptionText(string: card.description)
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print("count")
return card.imageUrls.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
print("here")
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "LatestCardsImage", for: indexPath as IndexPath) as! LatestCardImageCell
//let url = card.imageUrls[indexPath.row]
//cell.imageView.image = UIImage(named: "test")
cell.backgroundColor = UIColor.blue
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 150, height: 150)
}
LatestCardImageCell: UICollectionViewCell
@IBOutlet weak var imageView: UIImageView!
Edit 2: Summary of suggestions I've tried
People have suggested setting the dataSource and delegate for the CollectionView inside the cellForRowAt
call where I build the CollectionView:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LatestCardCell", for: indexPath) as! LatestCardsTableViewCell
cell.cardImagesCollection.delegate = cell
cell.cardImagesCollection.dataSource = cell
cell.backgroundColor = UIColor.clear
cell.card = cards[indexPath.row]
return cell
}
This did not change anything. They also suggested adding the following inside of that cellForRowAt call right after setting cell.card:
cell.cardImagesCollection.reloadData()
This also did not change anything.
I've put breakpoints and logging in my TableViewCell's custom class and I can see that numberOfItemsInSection
gets calls once per TableViewCell, and it returns the correct number (this number varies between TableViewCell). I then also see sizeForItemAt
get called the exact amount of times that numberOfItemsInSection
returns. I do not, however, see the cellForItemAt
method get called ever.
Here's the logging:
numberOfItemsInSection: 6
sizeForItemAt: Section 0 Row 0
sizeForItemAt: Section 0 Row 1
sizeForItemAt: Section 0 Row 2
sizeForItemAt: Section 0 Row 3
sizeForItemAt: Section 0 Row 4
sizeForItemAt: Section 0 Row 5
numberOfItemsInSection: 2
sizeForItemAt: Section 0 Row 0
sizeForItemAt: Section 0 Row 1
numberOfItemsInSection: 4
sizeForItemAt: Section 0 Row 0
sizeForItemAt: Section 0 Row 1
sizeForItemAt: Section 0 Row 2
sizeForItemAt: Section 0 Row 3
Some have suggested making sure to define cellForItemAt
by using autocomplete as opposed to copying and pasting, which is how I did it in the first place. I also have my custom TableViewCell set up with the following protocols UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout
and it does not complain about a lack of cellForItemAt
method. I currently have the delegate and dataSource set in the InterfaceBuilder and that is what is giving me the method calls I'm seeing.
I've tried calling reloadData()
on the collectionView in multiple places (the second I set the cell.card
in my cellForRowAt
, in my didSet
call, and even the awakeFromNib
method in the custom TableViewCell. Nothing works.
Other aspects of the TableCell render, but not this image collection. I've hardcoded a size for the CollectionView cells in the InterfaceBuilder, and even overrode sizeForItemAt to always return CGSize(width: 150, height: 150)
, just to be sure that the issue isn't having a cell that's too small to be visible. The tableView cell is set to auto height with latestCardsTableView.rowHeight = UITableViewAutomaticDimension
, and I've added long text to my labels to ensure that they do grow in size with the text automatically.
Does anyone have any other ideas? Are there things I can screenshot from the InterfaceBuilder, or some Swift code I can write to force some AutoLayout stuff? I'm open to anything.
Edit 3: A glimmer of hope
I've found that if I give my UITableViewCell an explicit large height, the UICollectionView does show up and does call cellForItemAt
. So, how do I set my constraints so that the UICollectionView forces the UITableViewCell larger, given that I've got rowHeight = UITableViewAutomaticDimension
set on my TableView?