How to Get Section of UItableview from Inside a Child UIcollectionview

How to get section of UITableView on a child UICollectionView

There are few issues here:

  1. Model naming
    The data model object you use is confusing. MovieModel sounds like it should represent a single movie. But looking at parsing functions,

            self.nowPlayingMovies.page = tempMovies.page
    self.nowPlayingMovies.total_results = tempMovies.total_results
    self.nowPlayingMovies.total_pages = tempMovies.total_pages
    self.nowPlayingMovies.results = tempMovies.results

    it looks like there are multiple entries in that object. It should probably be called MovieCategoryModel.
    HomeScreenCategoriesTableViewCell should have a model that looks like this:

    var movieCategory: MovieCategoryModel!

Since you are going to have different movies in
different sections, movieCategory property should not be static.


  1. cellForItemAt indexPath In this method you are trying to configure cell UI with the data about the movie. But the properties of HomeScreenCategoriesTableViewCell was never populated.

  2. numberOfItemsInSection
    This should return the number of movies in that section. Your code returns 5 - which is some arbitrary number. That's the issue for the error. You should return movieCategory.total_results

  3. cellForRowAt indexPath
    In HomeScreenCategoriesViewController when you dequeue HomeScreenMovieTableViewCell, you need to pass the movies to that cell, so it will have data to present. You need to do something like:

    if section == 0 {
    cell.movieCategory = popularMovies
    } else if section == 1 {
    cell.movieCategory = nowPlayingMovies
    }

  4. In general, from the parsing code, you need to save the movies separately for each category. That way in the tableView delegate methods you can easily fetch the data you need for the section.

  5. Parsing code also needs some work, as I can see you are cycling through the items contained within the object

    for i in 0..<(self.nowPlayingMovies.results?.count ?? 0)

but adding the whole object to the array within that same loop

`HomeScreenCategoriesViewController.movies.append(self.nowPlayingMovies)`

Edit based on extra information provided:

MovieResults is very confusing name for an object that represents a single Movie. I would suggest changing it to just Movie.
Then MovieModel - the object that contains multiple movies, would be a MovieCategory. Maybe it's also a good idea to store the title of that category within the object itself?

Models

struct Movie: Codable, Equatable {

let id: Int?
let title: String?
let overview: String?
let adult: Bool?
let original_language: String?
var poster_path: String?
var backdrop_path: String?
let vote_average: Float?
let release_date: String?
}

struct MovieCategory: Codable {
var title: String?
var page: Int?
var total_results: Double?
var total_pages: Int?
var results: [Movie]?
}

View Controller

import UIKit

class HomeScreenCategoriesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

@IBOutlet weak var tableView: UITableView!
var moviesCategories: [MovieCategory] = []

override func viewDidLoad() {
super.viewDidLoad()

tableView.rowHeight = 130
tableView.tableFooterView = UIView()
parsePopularMovies()
parseNowPlayingMovies()

}

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

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let category = moviesCategories[section]
return category.title
}

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "HomeScreenMovieTableViewCell", for: indexPath) as? HomeScreenCategoriesTableViewCell
{
cell.movieCategory = moviesCategories[indexPath.section]
return cell
}
return UITableViewCell()
}

func parsePopularMovies() {

let jsonUrlString = "URLwithMyAPIkey"
guard let url = URL(string: jsonUrlString) else { return }

URLSession.shared.dataTask(with: url) { (data, response, err) in

guard let data = data else { return }

do {
var popularMovies = try
JSONDecoder().decode(MovieCategory.self, from: data)
popularMovies.title = "Popular Movies"

for i in 0..<(popularMovies.results?.count ?? 0) {
let tempPosterPath = "https://image.tmdb.org/t/p/w500" + (popularMovies.results?[i].poster_path)!!
let tempBackDropPath = "https://image.tmdb.org/t/p/w500" + (popularMovies.results?[i].backdrop_path)!!
popularMovies.results?[i].poster_path = tempPosterPath
popularMovies.results?[i].backdrop_path = tempBackDropPath
}
self.moviesCategories.append(popularMovies)
DispatchQueue.main.async {
self.tableView.reloadData()
}

} catch let jsonErr {
print("Error serializing json:", jsonErr)
}
}.resume()

}

func parseNowPlayingMovies() {

let jsonUrlString = "URLwithMyAPIkey"
guard let url = URL(string: jsonUrlString) else { return }

URLSession.shared.dataTask(with: url) { (data, response, err) in

guard let data = data else { return }

do {
var nowPlayingMovies = try
JSONDecoder().decode(MovieCategory.self, from: data)

for i in 0..<(nowPlayingMovies.results?.count ?? 0) {
let tempPosterPath = "https://image.tmdb.org/t/p/w500" + (nowPlayingMovies.results?[i].poster_path)!!
//let tempBackDropPath = "https://image.tmdb.org/t/p/w500" + (self.nowPlayingMovies.results?[i].backdrop_path)!!
nowPlayingMovies.results?[i].poster_path = tempPosterPath
}
self.moviesCategories.append(nowPlayingMovies)
DispatchQueue.main.async {
self.tableView.reloadData()
}
} catch let jsonErr {
print("Error serializing json:", jsonErr)
}
}.resume()

}

}

TableViewCell

class HomeScreenCategoriesTableViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

@IBOutlet var collectionView: UICollectionView!
var sectionIndex:Int?
var movieCategory: MovieCategory!

override func awakeFromNib() {

super.awakeFromNib()
self.collectionView.delegate = self
self.collectionView.dataSource = self

DispatchQueue.main.async {
self.collectionView.reloadData()
}

}

func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}

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

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeScreenMovieCell", for: indexPath) as! HomeScreenCategoriesCollectionViewCell

if indexPath.row < movieCategory.results?.count ?? 0 {
let movie = movieCategory.results?[indexPath.row]
cell.test.text = movie.title
}

return cell
}

}

How to get section of UITableView from inside a child UICollectionview

You can set the collectionView tag to make it.
CollectionView should be the subview of tableViewCell. That is the collectionView can be the property of your customize TableViewCell Seems you are using Prototype Cell.

class YourCustomizeTableViewCell: UITableViewCell {
let collectionView: CollectionView
...
}

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

let cell = tableView.dequeueReusableCell(withIdentifier: "HorizontalSlideCell", for: indexPath) as! YourCustomizeTableViewCell
cell.collectionView.tag = indexPath.row

return cell
}

...

func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "InnerCollectionViewCell",
for: indexPath as IndexPath)

//indexPath.section is the collectionview section index but needs to be its parent tableview section's index. How do I get it?
cellCharLabel?.text = Languages.sharedInstance.alphabets[collectionView.tag].set[indexPath.row].char
...
return cell
}

Stored selected indexPath of UICollectionView inside UITableView

This will only work based on the assumption that both your parent table view and child collection views both are not using multiple sections with multiple rows and you only need to store one value for each to represent where an item is located in each respective view.

If I am understanding correctly, you have a collection view for each table view cell. You are storing the selection of each collection view, but you need to also know the position of the collection view in the parent table? A way to do this would be to add a property to your UICollectionView class or use the tag property and set it corresponding section it is positioned in the parent table. Then when you save the selected IndexPath, you can set the section to be that collection view's property you created(or tag in the example) so that each selected indexPath.section represents the table view section, and the indexPath.row represents the collection view's row.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//...
let collectionView = UICollectionView()
collectionView.tag = indexPath.section
//...
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
indexPath.section = collectionView.tag
let strData = itemFilter[indexPath.section].value[indexPath.item]
//...

}

Basically each selected index path you save will correspond to the following:

indexPath.section = table view section

indexPath.row = collection view row

IndexPath(row: 5, section: 9) would correlate to:

--table view cell at IndexPath(row: 0, section: 9) .

----collection view cell at IndexPath(row: 5, section: 0)

Edit: This is how you can use the saved index paths in your current code

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//...
let tempIndexPath = IndexPath(row: indexPath.row, section: collectionView.tag)
if arrSelectedIndex.contains(tempIndexPath) {
//...
} else {
//...
}
//...

}

UICollectionView inside UITableViewCell returning empty always even though shows as selected

You are trying to get a reusable cell in willMove(toParent parent: UIViewController?) , this is not going to return you a expected cell.

You need to get the cell , using a indexPath .

func cellForRow(at indexPath: IndexPath) -> UITableViewCell?

Table view inside of a collection view

Your UICollectionViewCell Class should confirm to Protocols, UITableViewDelegate and UITableViewDataSource

import UIKit
class CollectionViewCell: UICollectionViewCell,UITableViewDelegate,UITableViewDataSource {

//MARK: TableViewDelegateAndDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//Configure your cell here
return UITableViewCell()
}
}

Finally don't forget to assign TableView DataSource and Delegate in your storyboard

Access Parent tableViewCell from Child CollectionViewCell

please try this

  guard  let lbl = (self.yourTableView.cellForRow(at: [NSIndexPath(row: 0, section: 0) as IndexPath]) as! yourCellNameInTableView).labelName else {
return
}
lbl.text = "Your text"

Please pass your row number and section number. It may helps to you.Thanks you

UICollectionView nested in UITableViewCell does not update using DispatchQueue after receiving new data

You shouldn't call dequeueReusableCell anywhere but in cellForRowAt.

In order to get the currently displayed cell (if any) you use cellForRowAt:; this may return nil if the row isn't currently onscreen.

Once you have the cell you can reload it's data and refresh its collection view.

How to get UITableView row when user taps on UICollectionViewCell

To an extension of Subramanian Mariappan's concept and using delegate pattern to get informed in UIViewController about selection in collection view cell, please check your solution at https://github.com/sauvikapple/StackoverflowQ63802523.

Sample Image

Collection View inside table view delegate

Use closures to solve that.

Add a closure in CustomTableCell and call it when the collectionViewCell is tapped in collectionView(_:didSelectItemAt:) method, i.e.

class CustomTableCell: UITableViewCell {
var handler: (()->())?
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.handler?()
}
}

In MainViewController, set the closure while dequeuing CustomTableCell in tableView(_:cellForRowAt:) method, i.e.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableCell", for: indexPath) as! CustomTableCell
cell.handler = {[weak self] in
self.callSegue() //here.....
}
return cell
}

Also cross-check if you have a segue with identifier customSegue in your storyboard.



Related Topics



Leave a reply



Submit