collectionView cellForItemAt not being called

2019-07-29 03:45发布

问题:

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?

回答1:

Maybe you can do following, Write a method in your LatestCardsTableViewCell class,

func configureCell() {
      cardImagesCollection.reloadData()
}

and call this method, in HomeViewController's cellForRowAtIndexPath like following,

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]
cell. configureCell()
return cell

}