Collectionview reload not working when reload from custom tablecell.
I have put a dropdown inside one collectionview cell.this dropdown also not working.
Here is the code:
class HotelAvailableRoomsTVCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
//MARK: Life cycle
override func awakeFromNib() {
super.awakeFromNib()
let nib = UINib.init(nibName: "AvailableRoomCVCell", bundle: nil)
collectionView.register(nib, forCellWithReuseIdentifier: "AvailableRoomCVCell")
collectionView.delegate = self
collectionView.dataSource = self
// Initialization code
}
func initCellWithData(roomJSON:JSON,indexPath:IndexPath,isSingle:Bool) {
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
}
In viewController:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HotelAvailableRoomsTVCell", for: indexPath) as! HotelAvailableRoomsTVCell
cell.delegate = self
cell.initCellWithData(roomJSON: (json)!, indexPath: indexPath as IndexPath, isSingle: true)
return cell;
}
Screen is:
I have used a tableview with dynamic number of cells as collectionview. this collection view contains a dropdown as shown in image
First of all, do this & check
class HotelAvailableRoomsTVCell: UITableViewCell, UICollectionViewDelegate,UICollectionViewDataSource
You can also do this, (already done by me and its working),
Pass the data by creating var in HotelAvailableRoomsTVCell.
var collectionData : [String : Any] = []
In cellForRow
cell.collectionData = data
Related
I am studying how to create a simple app without storyboard and I have a problem:
I created a XIB called HomeViewController, inside it has a UICollectioView and made the registration of the cell in the viewDidLoad().
after that, I created a cell called HomeCollectionViewCell, put the identifier as "cell", in the cell it has a UILabelOutlet, that is referenced in the .swift file.
After setting the delegate and the datasource, it has the mandatory methods of the datasource, when making the cell configuration and calling the label by setting any text it returns nil. I don't know why this is happening, I've seen several videos on YouTube and none has solved the problem. Can anybody help me?
HomeViewController
class HomeViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
var info = ["Image"]
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(HomeCollectionViewCell.self, forCellWithReuseIdentifier:
"cell")
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension HomeViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection
section: Int) -> Int {
return info.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath:
IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for:
indexPath) as? HomeCollectionViewCell
cell?.teste.text = "test"
return cell!
}
}
HomeCollectionViewCell
class HomeCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var teste: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
}
That's because you have to register cell's nib not just class:
collectionView.register(UINib(nibName: "HomeCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "cell")
I try to show multiple collection views in one ViewController, but I get crash with error:
Thread 1: Exception: "could not dequeue a view of kind: UICollectionElementKindCell with identifier MainCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard"
I registered all the cells in Storyboard and this is my code for ViewController:
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var horizontalNumbers: UICollectionView!
#IBOutlet weak var verticalNumbers: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
horizontalNumbers.delegate = self
horizontalNumbers.dataSource = self
verticalNumbers.delegate = self
verticalNumbers.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == collectionView {
return 81
} else {
return 9
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == collectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MainCell", for: indexPath) as! CollectionViewCell
cell.backgroundColor = .systemGreen
return cell
} else if collectionView == horizontalNumbers {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Horizontal", for: indexPath) as! HorizontalNumbersCell
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Vertical", for: indexPath) as! VerticalNumbersCell
return cell
}
}
}
I checked everything twice and looked for some examples of code, but don't release why I get crash.
You need to register cell for all three collectionView.Take the collectionView for example.
try
collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "MainCell") // if it is loaded in nib, and nib name is CollectionViewCell
or
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "MainCell") // if it is written just in code
in the viewDidLoad.
Do the same thing for the horizontalNumbers, etc.
Check https://developer.apple.com/documentation/uikit/uicollectionview/1618089-register for more details.
I've created a UITableView inside my ViewController. Here's the code I've added to fill the TableView with content. However, no content is showing up. I've created a customized tableView Cell which I am calling in the cellNib as PostTableViewCell. When the program is running, it shows the prototype cells with the divider lines, but none of the custom content.
import Foundation
import UIKit
import Firebase
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView:UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView(frame: view.bounds, style: .plain)
//tableView.backgroundColor = UIColor.blue
let cellNib = UINib(nibName: "PostTableViewCell", bundle: nil)
tableView.register(cellNib, forCellReuseIdentifier: "postCell")
view.addSubview(tableView)
var layoutGuide:UILayoutGuide!
if #available(iOS 11.0, *) {
layoutGuide = view.safeAreaLayoutGuide
} else {
layoutGuide = view.layoutMarginsGuide
}
tableView.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: layoutGuide.topAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor).isActive = true
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
// Do any additional setup after loading the view.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 12
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
You're not actually configuring the cell in your tableView:cellForRowAt: method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
return cell
}
Typically you need to insert values into the elements of your custom cell. The "content" of your cell label text, images etc is usually inserted into the cells elements in this method. If you look at the code in a new Xcode project you will see:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let object = objects[indexPath.row] as! NSDate
cell.textLabel!.text = object.description
return cell
}
Note the line retrieving the data: let object = objects[indexPath.row] as! NSDate
Followed by the line in setting the text value of the textLabel:
cell.textLabel!.text = object.description
Code looks right..
Make sure you have assign content to table cell in cellForRowAt datasource methods.
I've created a pretty simple test app. It includes a 3 view controllers. The main view controller has a table view, that uses custom cells. The other two view controllers are able to be accessed through the main view controller, each have collection views, and can go back to the main view controller.
Here is the memory issue. Anytime I click on any of the cells from the 3 view controllers, the memory usage increases. I ran the app while using the 'Leaks' profiling template and found no leaks. Also used the 'Allocations' profiling template, checked 2 of the view controllers (recorded the reference counts), and all the stored reference counts under my program were released.
I haven't been able to use the Debug Memory Graph as it keeps crashing Xcode...
Main View Controller
import UIKit
class TableViewController: UITableViewController, UISearchBarDelegate {
#IBOutlet weak var searchForTool: UISearchBar!
#IBOutlet weak var toolTable: UITableView!
var searchActive : Bool = false
var data = [" Alphabetical", " Numerical"]
var identities = ["A", "B"]
override func viewDidLoad() {
super.viewDidLoad()
toolTable.delegate = self
toolTable.dataSource = self
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell
cell.toolLabel.text = data[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vcName = identities[indexPath.row]
let viewController = storyboard?.instantiateViewController(withIdentifier: vcName)
self.navigationController?.pushViewController(viewController!, animated: true)
}
}
One of the other View Controllers (both identical)
import UIKit
class AlphabeticalViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var collectionView: UICollectionView!
var labelArray = [String]()
var identities = [String]()
override func viewDidLoad() {
super.viewDidLoad()
labelArray = ["Main", "Definitions", "Steps", "References", "Other"]
identities = ["C", "B", "B", "D", "E"]
self.navigationController?.setNavigationBarHidden(true, animated: false)
collectionView.delegate = self
collectionView.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return labelArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
let myLabel = cell.viewWithTag(1) as! UILabel
myLabel.text = labelArray[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vcName = identities[indexPath.row]
let viewController = storyboard?.instantiateViewController(withIdentifier: vcName)
self.navigationController?.pushViewController(viewController!, animated: true)
}
}
Custom Cell Class
import UIKit
class CustomCell: UITableViewCell {
#IBOutlet weak var toolLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
I will provide any other images if needed. Any help would be greatly appreciated.
Information I got using the allocation tool.
The commented out code is just a search feature that I don't need atm.
The problem seems to be inside the CustomCell, maybe some resources not deinitialized.
Do you have some code inside awakeFromNib() or setSelected(...)?
You have problem with your tableView and collection view. look at IBOutlets your tableView name is toolTable
#IBOutlet weak var toolTable: UITableView!
but inside your datasource for the tableView you're accessing the wrong tableView
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// this is the wrong tableView
/*
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell
*/
// you should use the tableview which you have declared
let cell = toolTable.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell
cell.toolLabel.text = data[indexPath.row]
return cell
}
You have the same problem with your CollectionViewControllers as well.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//accessing wrong collectionView
/*
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
*/
// here you have to use self because your have named your collectionView the same as collectionView
let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
let myLabel = cell.viewWithTag(1) as! UILabel
myLabel.text = labelArray[indexPath.row]
return cell
}
Note: Your TableViewController and CollectionViewController are already Controllers. wondering why you have another tableView and collection view IBOutlets. Use one at a time
Firstly, I want to give credit to #totiG for pointing out that the problem could be with the navigation controller, and he was right.
There are other smaller memory issues, but the biggest by far had to do with my navigation. I kept pushing controllers onto the navigation stack, without popping them.
Here is the code for my final solution.
I replaced:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vcName = identities[indexPath.row]
let viewController = storyboard?.instantiateViewController(withIdentifier: vcName)
self.navigationController?.pushViewController(viewController!, animated: true)
}
With:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.row == 0 {
if let navController = self.navigationController {
for controller in navController.viewControllers {
if controller is TableViewController {
navController.popToViewController(controller, animated: true)
}
}
}
} else {
let vcName = identities[indexPath.row]
let viewController = storyboard?.instantiateViewController(withIdentifier: vcName)
self.navigationController?.pushViewController(viewController!, animated: true)
}
}
So now instead of pushing from controller to controller without popping any of them off of the stack, I pop all of the previous controllers up to the 'TableViewController' when 'Main' is clicked.
class TableController: UIViewController {
#IBOutlet var ListTable: UITableView!
var list: [Dictionary<String, String>] = []
override func viewDidLoad() {
super.viewDidLoad()
let ListTable = UITableView(frame: view.bounds)
self.ListTable = ListTable
ListTable.dataSource = self
ListTable.delegate = self
initList()
}
func initList() {
// get list from firebase
self.ListTable.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = self.list[indexPath.row]
let cellIdentifier = "ListCell"
let cell = CustomCell(style: .default, reuseIdentifier: cellIdentifier)
cell.foodLabel?.text = item["Banana"]
return cell
}
}
extension QueueController: UITableViewDataSource, UITableViewDelegate {
}
CustomCell class:
import UIKit
class CustomCell: UITableViewCell
{
#IBOutlet weak var foodLabel: UILabel!
override func awakeFromNib()
{
super.awakeFromNib()
}
}
My data from firebase loads properly. On storyboard I have a normal view controller with a UITableView embedded inside of it. That table view is liked to my IBOutlet for my ListTable. In the table there is a cell with 3 labels. That cell has the identifier ListCell and it's class is CustomCell.
Edit: There is no error but my data isn't showing up.
This is because your Custom Cell does not dequeue properly. Try this one
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "ListCell"
var cell : ListCell? = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as! ListCell?
if (cell == nil) {
cell = Bundle.main.loadNibNamed("ListCell", owner: nil, options: nil)?[0] as? ListCell
}
cell?.backgroundColor = UIColor.clear
cell?.contentView.backgroundColor = UIColor.clear
return cell!
}
Perhaps try registering your cell in viewDidLoad
ListTable.register(UINib(nibName: "CustomCell", bundle: Bundle.main), forCellReuseIdentifier: "ListCell") //this is assuming that your nib is named "CustomCell"
Also, for the record, you should follow camel-case conventions and name your UITableView listTable
You did never add the TableView to your view... (or part go the code is missing )