1

I am implementing a collection view cell inside a table view cell but strange things are happening with the collection view indexPath.

The numberOfItemsinSection gets fired 3 times and then cellForItemAt only once when numberOfitemsInSection is 2. I expect one section and 2 cells for the collection view.

Here is the source data:

[["myDomain.jpg1", "myDomain.jpg2"]]

Here is the console output from the following code:

"number of items in section: 2"
"number of items in section: 2"
"number of items in section: 2"
"cell for item at [0, 0]"
"indexPath.section: 0"    
"indexPath.row: 0"    
"myDomain.jpg1"

Here is my view controller:

class WishListsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

var tableView: UITableView = UITableView()

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.delegate      =   self

    tableView.dataSource    =   self

    tableView.register(WishListsCell.self, forCellReuseIdentifier: cellId)

    self.view.addSubview(tableView)
}

func numberOfSections(in tableView: UITableView) -> Int {
    return wishLists.count // 1
}

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{

    let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! WishListsCell

    return cell
}

Here is my table view cell:

class WishListsCell: UITableViewCell {

var collectionView: UICollectionView!

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)

    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    layout.itemSize = CGSize(width: screenWidth, height: (screenWidth / 4))
    layout.minimumInteritemSpacing = 0
    layout.minimumLineSpacing = 0
    layout.estimatedItemSize.height = (screenWidth / 4)
    layout.estimatedItemSize.width = screenWidth

    collectionView = UICollectionView(frame: contentView.frame, collectionViewLayout: layout)

    collectionView.delegate = self

    collectionView.dataSource = self

    collectionView.register(WishListsCollectionViewCell.self, forCellWithReuseIdentifier: cellId)

    self.contentView.addSubview(collectionView)

}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}    
}

extension WishListsCell: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

    let items = wishListUrls[section]

    debugPrint("number of items in section: \(items.count)")

    return items.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! WishListsCollectionViewCell

    debugPrint("cell for item at \(indexPath)")

    debugPrint("indexPath.section: \(indexPath.section)")

    debugPrint("indexPath.row: \(indexPath.row)")

    if let imageUrl = wishListUrls[indexPath.section][indexPath.row] as String! {

        debugPrint(imageUrl)
markhorrocks
  • 1,199
  • 19
  • 82
  • 151
  • 2
    as a side note: here is a blog post about the pitfalls you can get in CollectionView inside a TableViewCell: https://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell-in-swift/ – muescha Jan 12 '17 at 23:50
  • in collectionview you should use `indexPath.item` instead of `indexPath.row` – muescha Jan 12 '17 at 23:51
  • It made no difference. It's my understanding that `indexPath.row` and `indexPath.item` are synonyms and can be interchanged – markhorrocks Jan 13 '17 at 08:02

2 Answers2

0

I don't see an implementation of numberOfSections(in collectionView) in your WishListsCell extension.

I can't be certain based on the snippets you've posted, but it might look something like.

func numberOfSections(in collectionView: UICollectionView) -> Int {
    return wishListUrls.count
}
Garrett Clyde
  • 306
  • 3
  • 9
  • I did have this implemented and it made no difference. I assumed it defaults to 1 and I've seen it missing in many code examples. – markhorrocks Jan 13 '17 at 07:51
  • Each table view cell should have 1 collection view section and multiple cells. – markhorrocks Jan 13 '17 at 08:07
  • Yeah... Sorry I can't be of more help. The amount of code needed to make this happen makes it difficult to reason about with only a few snippets in an SO post. Looks like you're going to have about 20 more of those `debugPrint` statements before you nail this one down. Haha. I'm sure you'll get it. Best of luck. – Garrett Clyde Jan 13 '17 at 22:09
0

Ultimately the chief problem came down to loading my data from 5 Alamofire requests as the master and detail is not yet available to me as single request from the API. tableView.reloadData() seems to fire repeatedly until I explicitly fire it in the first Alamofire completion. When I fake the detail data as a local dictionary it seems to work much better.

Apart from that, I implemented it like this Swift - how to open another viewcontroller with CollectionViewCell inside UITableViewCell

The only change was that I have multiple sections each with one row in my table cell so I made collectionView.tag use indexPath.section instead of indexPath.row.

I also used https://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell-in-swift/

and this

https://www.thorntech.com/2015/08/want-your-swift-app-to-scroll-in-two-directions-like-netflix-heres-how/

Community
  • 1
  • 1
markhorrocks
  • 1,199
  • 19
  • 82
  • 151