How to get section of UITableView on a child UICollectionView
There are few issues here:
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.resultsit 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
.
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.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 returnmovieCategory.total_results
cellForRowAt indexPath
InHomeScreenCategoriesViewController
when you dequeueHomeScreenMovieTableViewCell
, 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
}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.
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 sectionindexPath.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.
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
Combining Scenekit and Spritekit in a Single Screen
Swift: Gradient Splits on Rotation
How to Apply Impulse to The Node on Touch Angle
Protocol Variable Implementing Another Protocol
Swiching Between 2 Diferent Nsviewcontrollers with Data
Back to Table View from Detail Page Without Reload, Swift
Swift-Making an Sknode Simply "Move Forward" on an Angle
Issues with Uploading from Xcode 9 to App Store/ Itunes Connect
Midiclientcreate Does Not Work for 32 Bit Processors in Swift
Swift- Mkmapkit View Only One City
Prepareforsegue from a UIbutton in a Custom Prototype Cell
How to Properly Map JSON Properties to Model Properties in Realm.Create
Playing Multiple Wav Out Multiple Channels Avaudioengine
Swift: How to Get Image Name from Assets
Skphysicscontact Not Detecting Categorybitmask Collision
Pfuser That Created Object Cannot Delete Object Despite Acl Writing Access
Watchkit Extension Cannot Read from Icloud
Swiftui Tabview with List Not Refreshing After Objected Deleted From/Added to Core Data