I have a Tableview, I have a collectionView in it. There is imageView inside the CollectionView. As you can see in the photo at the moment, two TableViews are created separately. But the data in the CollectionViews inside this tableView is the same. Important: I have one collectionView. CollectionView is created according to the tableView Count. The collectionView's hps has the same data. I want to upload different data to CollectionViews, how can I do this? There is a well-known tableView for circumcision and weddings, but the CollectionView contents are the same. I have to do it differently.
For example, I want to add the data in davetiyefilee Array to 1.CollectionView. 2.I want to add the data from davetiyefilee2 Array to the CollectionView
enter image description here
enter image description here
UITableViewCell
class CategoryRow : UITableViewCell {
#IBOutlet weak var firstColView: UICollectionView!
var data = [String]()
var collectionData = [[String]]()
}
extension CategoryRow : UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return collectionData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellDav1", for: indexPath) as! anaSayfaCell
let rowValue = collectionData[indexPath.row]
for i in 0..<rowValue.count {
let deneme = collectionData[firstColView.tag][indexPath.item]
let urlNew = URL(string: deneme)
cell.denemeImage.sd_setImage(with: urlNew)
}
return cell
}
func setData(data: [String])
{
self.data = data
self.firstColView.reloadData()
}
func setDataa(collectionData: [[String]])
{
self.collectionData = collectionData
self.firstColView.reloadData()
}
}
MainView
extension anaSayfaViewController : UITableViewDelegate { }
extension anaSayfaViewController : UITableViewDataSource {
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return kategoriIsımYeni[section]
}
func numberOfSections(in tableView: UITableView) -> Int {
return kategoriIsımYeni.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CategoryRow
cell.setData(data: davetiyefilee)
cell.setDataa(collectionData: collectionData)
return cell
}
}
class anaSayfaViewController: UIViewController, UISearchBarDelegate {
var collectionData = [[String]]()
var davetiyefilee = [String]()
var davetiyefilee2 = [String]()
#objc func davetiyeCEK1(){
if let baslik = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
for review in baslik {
if let soru_baslik = review["davetiyefilee"] as? String {
let s = String(describing: soru_baslik)
self.davetiyefilee.append(s)
self.collectionData.append([s])
DispatchQueue.main.async { self.tableViewKategoriler.reloadData() } } } }
if let baslik = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
for review in baslik {
if let soru_baslik = review["davetiyefilee"] as? String {
let s = String(describing: soru_baslik)
self.davetiyefile2.append(s)
self.collectionData.append([s])
DispatchQueue.main.async {
self.tableViewKategoriler.reloadData()
} } } }}
Swift has a handy property to its Views called tag. You can assign a unique tag to each of your CollectionViews and then add your data based on a condition like:
if collectionView.tag == 0 {
\\ your first collection view data assignment
} else if collectionView.tag == 1 {
\\ your second collection view data assignment
collectionView here refers to the parameter given by the collectionView functions above. You can assign tags using storyboard, but it is better to do that programmatically if you have many collectionViews. A good article that covers this: https://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell-in-swift/
Related
How can I identify the first and last rows of each section in a dynamic tableview and make a view inside the cell class hidden.
For each first cell in each section I need to hide the topView, for each last row of each section, I need to hide the bottomView.
For example I have the following Class:
class cell: UITableViewCell {
#IBOutlet weak var topView: UIView!
#IBOutlet weak var bottomView: UIView!
}
I have tried to identify the last row of each section by doing the following, but it simple does not hide the correct bottomView, except for in the last section. Is there a way to identify the rows correctly?
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! cell
let item = sections[indexPath.section].items[indexPath.row]
structure = sections[indexPath.section].items
let totalRow = tableView.numberOfRows(inSection: indexPath.section)
if(indexPath.row == totalRow - 1)
{
cell.bottomView.isHidden = true
}
return cell
}
var sections = [mySections]()
var structure = [myStructure]()
Fetching Data:
private func fetchJSON() {
guard let url = URL(string: "test.com")
else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = "id=\1".data(using: .utf8)
URLSession.shared.dataTask(with: request) { data, _, error in
guard let data = data else { return }
do {
let decoder = JSONDecoder()
self.structure.sort { $0. datestamp > $1.datestamp }
let res = try decoder.decode([myStructure].self, from: data)
let grouped = Dictionary(grouping: res, by: { $0. datestamp })
let keys = grouped.keys.sorted()
self.sections = keys.map({mySections(date: $0, items: grouped[$0]!
)})
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
catch {
print(error)
}
}.resume()
}
Struct:
struct mySections {
let date : String
var items : [myStructure]
}
struct myStructure: Decodable {
let recordid: Int
let testname: Int
let datestamp: String
}
Example of Data:
[
{
"recordid": 1,
"testname": "Jen",
"datestamp": "2021-11-3"
},
{
"recordid": 1,
"testname": "Jake",
"datestamp": "2021-11-2"
}
]
Setting Up Sections:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let section = sections[section]
return section.items.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section].date
}
When you are in your delegate creating cells, you are in the process of telling the table view what rows and sections it has. That means that the table view hasn't finished setting up sections so it's not the right time to call tableView.numberOfRows(inSection:).
You're already pulling your data out of the model... in this case it looks like your model has an array of sections and each section has an array of rows, so ask the model whether or not the cell your building is at the beginning or end of its section:
import UIKit
import SwiftUI
import PlaygroundSupport
class CustomCell : UITableViewCell {
static let identifier = "CustomCell"
}
class DataSource : NSObject, UITableViewDataSource {
let sections = [
[
"Cow",
"Duck",
"Chicken"
],
[
"Lion",
"Zebra",
"Oryx"
],
]
func numberOfSections(in tableView: UITableView) -> Int {
sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let newCell = tableView.dequeueReusableCell(withIdentifier: CustomCell.identifier, for: indexPath)
if let cell = newCell as? CustomCell {
cell.textLabel?.text = sections[indexPath.section][indexPath.row]
if indexPath.row == 0 {
cell.textLabel?.backgroundColor = UIColor.yellow
}
if indexPath.row == sections[indexPath.section].count - 1 {
cell.textLabel?.backgroundColor = UIColor.gray
}
}
return newCell
}
}
let tableView = UITableView(frame: CGRect(x: 0, y: 0, width: 320, height: 480))
tableView.register(CustomCell.self, forCellReuseIdentifier: CustomCell.identifier)
let dataSource = DataSource()
tableView.dataSource = dataSource
PlaygroundSupport.PlaygroundPage.current.liveView = tableView
I know the issue is regarding scope; I just dont know if theres an easy fix I can do without changing my code much. but open to anything
import UIKit
import Firebase
import FirebaseAuth
import FirebaseFirestore
class AdminViewController: UIViewController, UITableViewDelegate,
UITableViewDataSource {
#IBOutlet var custodianRunReportsTableView: UITableView!
var dbRef: DatabaseReference!
var data = [String]()
override func viewDidLoad() {
super.viewDidLoad()
startObservingDB()
custodianRunReportsTableView.delegate = self
custodianRunReportsTableView.dataSource = self
// Do any additional setup after loading the view.
}
// Gets users' names from Cloud Firestore Database
func startObservingDB() {
let db = Firestore.firestore()
let namesDocumentRef = db.collection("Users").document("Names")
namesDocumentRef.addSnapshotListener { DocumentSnapshot, error in
guard let document = DocumentSnapshot else {
print("Error fetching document: \(error!)")
return
}
guard let data = document.data() else {
print("Document data was empty.")
return
}
let values = data.values
let rowNumber = data.count
print("Current data: \(data)")
print("Current data has the values: \(values)")
print("Current data totals \(data.count) items.")
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You tapped me!")
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rowNumber
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = custodianRunReportsTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = values[indexPath.row]
print("Names in cell: \(values)")
print("\(data)")
return cell
}
}
UPDATED CODE:
This is updated after an answer to the original post. The code no longer has the unresolved identified error; however, the table view does not display any cell text and is empty.
class AdminViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var custodianRunReportsTableView: UITableView!
var valuesArray:[String] = []
var data:[String] = []
var namesDocumentRef:DocumentReference!
override func viewDidLoad() {
super.viewDidLoad()
startObservingDB()
custodianRunReportsTableView.delegate = self
custodianRunReportsTableView.dataSource = self
}
// Gets users' names from Cloud Firestore Database
func startObservingDB() {
var namesDocumentRef:DocumentReference!
let db = Firestore.firestore()
namesDocumentRef = db.collection("Users").document("Names")
namesDocumentRef.addSnapshotListener { DocumentSnapshot, error in
if error != nil{
return
}
else {
guard let snapshot = DocumentSnapshot, snapshot.exists else {return}
guard let data = snapshot.data() else { return }
self.valuesArray = Array(data.values) as! Array<String>
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You tapped me!")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return valuesArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = custodianRunReportsTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = valuesArray[indexPath.row]
return cell
}
}
The variables data,values and rowCount are inside closure so you can't just write values[indexPath.row] because you can't return from inside closure. Usually completionHandlers are used for this purpose, but in this scenario, you should put the values inside an array and then use inside the tableview. Let me show you how to do.
At the start of your viewController, declare a string array.
var valuesArray:[String] = []
Then, inside modify your startObservingDB() function
func startObservingDB() {
var docRef:DocumentReference!
let db = Firestore.firestore()
docRef = db.collection("Users").document("Names")
docRef.addSnapshotListener { (docSnapshot, error) in
if error != nil {
return
}
else {
guard let snapshot = docSnapshot, snapshot.exists else {return}
guard let data = snapshot.data() else { return }
self.valuesArray = Array(data.values) as! Array<String>
self.tableView.reloadData()
}
}
}
In viewDidLoad call this function
startObservingDB()
Then in tableView methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ValuesArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = custodianRunReportsTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = valuesArray[indexPath.row]
return cell
}
In your class AdminViewController you can reference properties defined outside of methods with self (in your example you have dbRef that you can reference like self.dbRef in methods).
So I suggest you make properties for data, value and rowNumber and change them in startObservingDB method rather than declare them. This way you will be able to reference them in tableView methods.
I create a View Controller that contains a UITableView and each UITableViewCell contains a UICollectionView. My problem is that I can't have a different result on every CollectionView. I parse data with JSON. I have a static array but it looks like its empty.
In cellForItemAt, I get an error: Index out of range.
Here is my ViewController
import UIKit
class HomeScreenCategoriesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var moviesCategories = ["Popular", "Now Playing", "Latest", "Top Rated", "Upcoming"]
var popularMovies = MovieModel()
var nowPlayingMovies = MovieModel()
static var movies: [MovieModel] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = 130
tableView.tableFooterView = UIView()
parsePopularMovies()
parseNowPlayingMovies()
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "\(moviesCategories[section])"
}
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
{
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 {
let tempMovies = try
JSONDecoder().decode(MovieModel.self, from: data)
self.popularMovies.page = tempMovies.page
self.popularMovies.total_results = tempMovies.total_results
self.popularMovies.total_pages = tempMovies.total_pages
self.popularMovies.results = tempMovies.results
for i in 0..<(self.popularMovies.results?.count ?? 0) {
let tempPosterPath = "https://image.tmdb.org/t/p/w500" + (self.popularMovies.results?[i].poster_path)!!
let tempBackDropPath = "https://image.tmdb.org/t/p/w500" + (self.popularMovies.results?[i].backdrop_path)!!
self.popularMovies.results?[i].poster_path = tempPosterPath
self.popularMovies.results?[i].backdrop_path = tempBackDropPath
HomeScreenCategoriesViewController.movies.append(self.popularMovies)
}
} 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 {
let tempMovies = try
JSONDecoder().decode(MovieModel.self, from: data)
self.nowPlayingMovies.page = tempMovies.page
self.nowPlayingMovies.total_results = tempMovies.total_results
self.nowPlayingMovies.total_pages = tempMovies.total_pages
self.nowPlayingMovies.results = tempMovies.results
for i in 0..<(self.nowPlayingMovies.results?.count ?? 0) {
let tempPosterPath = "https://image.tmdb.org/t/p/w500" + (self.nowPlayingMovies.results?[i].poster_path)!!
//let tempBackDropPath = "https://image.tmdb.org/t/p/w500" + (self.nowPlayingMovies.results?[i].backdrop_path)!!
self.nowPlayingMovies.results?[i].poster_path = tempPosterPath
HomeScreenCategoriesViewController.movies.append(self.nowPlayingMovies)
}
} catch let jsonErr {
print("Error serializing json:", jsonErr)
}
}.resume()
}
}
and here is my TableViewCell
import UIKit
class HomeScreenCategoriesTableViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet var collectionView: UICollectionView!
var sectionIndex:Int?
static var movies: [MovieModel] = []
override func awakeFromNib() {
super.awakeFromNib()
self.collectionView.delegate = self
self.collectionView.dataSource = self
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeScreenMovieTableViewCell", for: indexPath) as! HomeScreenCategoriesTableViewCell
cell.sectionIndex = indexPath.section
return cell
}
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
cell.test.text = HomeScreenCategoriesTableViewCell.movies[collectionView.tag].results?[indexPath.row].title!
return cell
}
}
My model is this:
struct MovieResults: 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 MovieModel: Codable {
var page: Int?
var total_results: Double?
var total_pages: Int?
var results: [MovieResults]?
}
I tried to follow this instruction (How to get section of UITableView from inside a child UICollectionview) but I can't find a solution
What am I doing wrong?
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.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.
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 return movieCategory.total_results
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
}
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
}
}
I'm trying to create a tableView within a viewController. I know it is annoying, but the table looks much better that way. I am also trying to incorporate data from Firebase to put into the table. Unfortunately when I run the code, it only shows a blank table. The console was able to print the desired data, but it just won't show on the actual table. Please let me know what I'm doing wrong. Many thanks!
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var user = Auth.auth().currentUser
var users = [Users]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.reloadData()
fetchUser()
}
func fetchUser() {
Database.database().reference(fromURL: "https://yala-2018.firebaseio.com/").child("users").observe(.childAdded, with: { (DataSnapshot) in
if let dictionary = DataSnapshot.value as? [String: AnyObject] {
let user = Users()
// user.setValuesForKeys(dictionary)
user.name = dictionary["name"] as! String
user.age = dictionary["age"] as! String
user.sex = dictionary["sex"] as! String
self.users.append(user)
print(user.name, user.age)
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
})
}
func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return users.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "guide", for: indexPath)
let user = users[indexPath.row]
cell.textLabel?.text = user.name
cell.detailTextLabel?.text = "Age: \(user.age) Sex: \(user.sex)"
// Configure the cell...
return cell
}
func tableView(tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
Change this to 1 as by 0 you mean no sections which will display empty tableView even if there is a data , or remove it as by default it's 1
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
I want to parse JSON data from a local file that is available in the project and then populate these data to UITableView.
My Requirements
parse the json data from local path not from URL
Populate the json data to UITableView
Facing problems
Unable to display the parsed data, ( bracket is displaying in the table view.
I am able to print the data in console using dump() but unable to print data in tableView
Updated view controller for passing data to another controller.
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return lookArrayModel.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cells = myTableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let displayData = lookArrayModel[indexPath.row]
cells.textLabel?.text = String(describing: displayData.Lookname!)
cells.detailTextLabel?.text = String(describing: displayData.Lookdetails!)
// print(displayData.shadeModel)
return cells
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = myTableView.indexPathForSelectedRow;
let currentCell = myTableView.cellForRow(at: indexPath!) as UITableViewCell!;
lookNameValue = currentCell?.textLabel?.text
lookDetailValue = currentCell?.detailTextLabel?.text
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//let lookShade = LookModelData()
if (segue.identifier == "segueToLook") {
let destController:DetailsViewController = segue.destination as! DetailsViewController
//Set the selecte row index value
destController.LabelText = String(describing: lookNameValue)
destController.DetailText = String(describing: lookDetailValue)
// destController.arrayData = lookShade.shadeModel as! NSMutableArray
}
}
}
Destination view controller. Swift
class DetailsViewController:UIViewController,UITableViewDataSource,UITableViewDelegate {
var lookArrayModel = [LookModelData]()
var arrayData: NSMutableArray = []
#IBOutlet weak var secondView: UITableView!
var LabelText = String()
var DetailText = String()
var shadeText = String()
#IBOutlet weak var LookLabel: UILabel!
#IBOutlet weak var LookName: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
print(arrayData)
LookName?.text = LabelText
LookLabel?.text = DetailText
secondView.dataSource = self
secondView.delegate = self
secondView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayData.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cells = secondView.dequeueReusableCell(withIdentifier: "secondCell", for: indexPath)
let displayData = arrayData
// cells.textLabel?.text = String(describing: (displayData as AnyObject))
// print(arrayData)
return cells
}
}
Please check my code :
Changed lookArrayModel type NSMutableArray to [LookModelData]. Like those I did some changes. Please check.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var lookArrayModel = [LookModelData]()
#IBOutlet weak var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
guard let Path = Bundle.main.path(forResource: "ColorShade", ofType: "json") else { return }
let url = URL(fileURLWithPath: Path)
do {
let data = try Data(contentsOf: url)
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
myTableView.dataSource = self
myTableView.delegate = self
//Calling the function for adding look
createLooks(dictionary: json as! NSArray)
myTableView.reloadData()
} catch {
print(error)
}
}
func createLooks(dictionary:NSArray) {
for item in dictionary {
let item1 = item as! NSDictionary
let lookModal = LookModelData()
lookModal.Lookname = item1.value(forKey: "Lookname") as? String
lookModal.LookId = item1.value(forKey: "LookId") as? String
lookModal.Lookdetails = item1.value(forKey: "Lookdetails") as? String
lookModal.shadeModel = createshade(shades: item1.value(forKey: "shades") as! NSArray)
lookArrayModel.append(lookModal)
}
}
func createshade(shades: NSArray) -> [ShadeDescription] {
var arrayShade = [ShadeDescription]()
for item in shades
{
let item1 = item as! NSDictionary
let shadeModal = ShadeDescription()
shadeModal.comboID = item1.value(forKey: "comboID") as? String
shadeModal.shadeName = item1.value(forKey: "shadeName") as? String
shadeModal.ShadeType = item1.value(forKey: "ShadeType") as? String
shadeModal.ShadeCode = item1.value(forKey: "shadeCode") as? String
arrayShade.append(shadeModal)
}
return arrayShade
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return lookArrayModel.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cells = myTableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let displayData = lookArrayModel[indexPath.row]
// You will get like this
// print(displayData.LookId!)
// print(displayData.Lookname!)
// print(displayData.Lookdetails!)
// print(displayData.shadeModel!)
// This is the way to get shade model data
if let shadeModels = displayData.shadeModel {
for var shadeModel in shadeModels {
print(shadeModel.comboID)
print(shadeModel.ShadeType)
print(shadeModel.shadeName)
print(shadeModel.ShadeCode)
}
}
cells.textLabel?.text = String(describing: displayData.Lookname!)
return cells
}
}
class LookModelData
{
var Lookname:String?
var LookId:String?
var Lookdetails:String?
//Shades Array
var shadeModel : [ShadeDescription]?
}
class ShadeDescription {
var ShadeType:String?
var shadeName:String?
var comboID:String?
var ShadeCode:String?
}