I can't show data in UITableView - swift

I'm new to swift, I made a simple table and added 21 data in it.
When I debug, the compiler enters here, I see that there are 21.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(menus.count)
return menus.count
}
but it doesn't go into this part
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "mCell", for: indexPath) as! HomeViewCell
let men = menus[indexPath.row]
print(men.Title)
cell.mTitle.text = men.Title
cell.subTitle.text = men.SubTitle
return cell
}
I'm learning new things from books, videos, sorry for the newbie question
I think I've done all the work but I couldn't figure out what I'm skipping I watched too many videos and I'm confused
all code,
class ViewController: UIViewController , UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var menuTable: UITableView!
var menus = [Menu]()
override func viewDidLoad() {
super.viewDidLoad()
loadMenus()
}
override func viewDidLayoutSubviews(){
}
func loadMenus(){
for index in 0...20 {
menus.insert(Menu(Image: "0", Title: "String \(index)", SubTitle: "String"), at: index)
}
self.menuTable.reloadData()
// DispatchQueue.main.async {
//
// }
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(menus.count)
return menus.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "mCell", for: indexPath) as! HomeViewCell
let men = menus[indexPath.row]
print(men.Title)
cell.mTitle.text = men.Title
cell.subTitle.text = men.SubTitle
return cell
}
}
class HomeViewCell: UITableViewCell {
#IBOutlet weak var mTitle: UILabel!
#IBOutlet weak var subTitle: UILabel!
#IBOutlet weak var mImage: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}

I tried your code and everything works well.
The only thing I can think of:
Make sure you have assigned the class to the table view cell and connected the outlets.
What you showed me above is the identifier. See below for class.
After I do this, I see the result:
Output in the console
21
21
21
String 0
String 1
String 2
String 3
String 4
String 5
String 6
String 7
String 8
String 9
String 10
String 11
String 12
String 13
String 14
Can you confirm you assigned HomeViewCell class to the Cell in storyboard ?
Update
You use auto layouts to set up your table and give the cell a height of 138 but you do not add any constraints for the subviews within your cell so I believe the runtime is unable to determine the actual height of your cell if the subviews in the cell do not have proper constraints.
add this UITableView delegate method and run your app to see if you see results:
func tableView(_ tableView: UITableView,
heightForRowAt indexPath: IndexPath) -> CGFloat {
return 138
}
Of Course, change 138 to whatever you want or better yet configure your cell layout in autolayout.
End result:

Try adding this in viewDidLoad:
menuTable.register(HomeViewCell.self, forCellReuseIdentifier: "mCell")

Related

Swift UITableview Reload Cell

I'm stuck with the following, any inputs would be highly appreciated.
My app has a UITableViewController with custom cells. Let's name its UITableView as TABLE VIEW-1. I am using XIB as its custom cell. Inside that xib, there is another UITableView, (TABLE VIEW-2), with another XIB as its custom cell.
My question is, How can I reload cells of (TABLE VIEW-2) from (TABLE VIEW-1) once I get data from an API in (TABLE VIEW-1). I want to use delegate and protocols to do this.
OR, What would be the correct way of performing this and how would I go about it?
Create a reference of TableView1 in the TableView2 ViewController. You can do this by
-- Open the Assistant Editor
-- Right-click and drag from your UI element (i.e. label) to the code file
-- Xcode auto inserts code for you to create the name and connection
Then call tableView2.reloadData(), where tableView2 is the name of the outlet you just created.
Create a reference of the TABLE VIEW-2 in the TABLE VIEW-1 custom cell (TABLE VIEW-1 CELL)
Create a method inside TABLE VIEW-1 CELL to reload its data alone with the TABLE VIEW-2 (Optional but useful to organize your code)
Inside the tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell of the TABLE VIEW-1 call reload function
class ViewController: UIViewController {
#IBOutlet weak var mainTable: UITableView!
let sampleData = [
(section: "News", SubSections: [
"Breaking news",
"Current Affairs",
"Local"
]) ]
override func viewDidLoad() {
super.viewDidLoad()
self.mainTable.estimatedRowHeight = 200
self.mainTable.rowHeight = UITableView.automaticDimension
let nib: UINib = UINib(nibName: String(describing: MainCell.self), bundle: Bundle.main)
self.mainTable.register(nib, forCellReuseIdentifier: String(describing: MainCell.self))
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
self.sampleData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: MainCell = tableView.dequeueReusableCell(withIdentifier: String(describing: MainCell.self), for: indexPath) as! MainCell
let sectionData = self.sampleData[indexPath.row]
cell.setUpData(title: sectionData.section, data: sectionData.SubSections)
return cell
}
}
class MainCell: UITableViewCell {
#IBOutlet weak var sectionTitle: UILabel!
#IBOutlet weak var internalTable: UITableView!
var tableData:[String]?
override func awakeFromNib() {
super.awakeFromNib()
self.internalTable.estimatedRowHeight = 200
self.internalTable.rowHeight = UITableView.automaticDimension
let nib: UINib = UINib(nibName: String(describing: InsideCell.self), bundle: Bundle.main)
self.internalTable.register(nib, forCellReuseIdentifier: String(describing: InsideCell.self))
}
func setUpData(title: String, data:[String]) {
self.sectionTitle.text = title
self.tableData = data
self.internalTable.reloadData()
}
}
extension MainCell: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
self.tableData?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: InsideCell = tableView.dequeueReusableCell(withIdentifier: String(describing: InsideCell.self), for: indexPath) as! InsideCell
if let subSectionData = self.tableData?[indexPath.row] {
cell.subSectionTitle.text = subSectionData
}
return cell
}
}
class InsideCell: UITableViewCell {
#IBOutlet weak var subSectionTitle: 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
}
}

TableViewCell does not get data in Swift

I am using a Custom TableViewCell in TableViewController.
Even the data is getting populated but my TableViewCell does not display it.
Here is my Custom TableViewCell Code
class PlaceItemCellCustom: UITableViewCell {
#IBOutlet weak var placeFace: UILabel?
#IBOutlet weak var placeName: UILabel?
override func awakeFromNib() {
super.awakeFromNib()
}
}
Here is my TableViewContoller
class PlaceListViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
loadListFromSource()
}
// Other code
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return places.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let place = places[indexPath.row]
// I am getting the data
print(place.placeName?.description ?? " " )
let customCell = tableView.dequeueReusableCell(withIdentifier: "PlaceListIdentifier", for: indexPath) as! PlaceItemCellCustom
customCell.placeName?.text = place.placeName
return customCell
}
}
What am I missing here? I am new to IOS app development.
Found similar questions but did not help
Edit: It was working fine for the default TableViewCell.
But when I changed it to custom TableViewCell it does not work. I have set the class name in the storyboard as well.
Here is my Storyboard
Here is the output
As much as I can understand you must have forgotten to connect the IBOutlet of placeName in PlaceItemCellCustom:
In your PlaceItemCellCustom keep placeName as :
#IBOutlet weak var placeName: UILabel!
and in cellForRowAt:
customCell.placeName.text = place.placeName
in this way if you forgot to connect segue Xcode will throw error as :
Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
You can read more about it here :
https://cocoacasts.com/should-outlets-be-optionals-or-implicitly-unwrapped-optionals
You need using this method for get data.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return places.count
}

UITableViewCell not updating UISwitch when selecting row

I have a UITableViewCell that contains a bunch of UISwitches. I want the switch to toggle on/off based on what row the user selects, the data is passing to my cell but the switch state is not updating.
I am using a basic MVC, the Storyboard has a TableView > TableViewCell > Label | UISwitch
Controller:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var testList = [1,2,3,4,5]
#IBOutlet weak var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
table.tableFooterView = UIView()
table.delegate = self
table.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return testList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseCell") as! SwitchCell
//Turn them all on at start
cell.setSwitch(rowSelected: true)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseCell") as! SwitchCell
cell.setSwitch(rowSelected: false)
}
}
SwitchCell
class SwitchCell: UITableViewCell {
#IBOutlet weak var uiswitch: UISwitch!
#IBOutlet weak var label: UILabel!
func setCell(number: Int){
label.text = String(number)
}
func setSwitch(rowSelected:Bool) {
uiswitch.setOn(rowSelected, animated: true)
}
}
I know I can just make the UISwitch intractable, but I am looking at changing it's state when the user selects the row.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseCell") as! SwitchCell
cell.setSwitch(rowSelected: false)
}
is incorrect. Using this code you don't pick the cell you want.
You should do simething like this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let cell = tableView.cellForRow(at: indexPath) as! SwitchCell
cell.setSwitch(rowSelected: false)
}
First of all, we don't dequeue the cell in didSelectRowAt method. Never do that. This will dequeue a brand new cell and won't reflect any changes that you do in it.
So remove the code for tableView(_: didSelectRowAt:) method.
Secondly, you can simply handle the UISwitch state based on cell selection in SwitchCell's definition using setSelected(_:animate:) method like so,
class SwitchCell: UITableViewCell {
#IBOutlet weak var uiswitch: UISwitch!
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
uiswitch.setOn(selected, animated: true)
}
//rest of the code...
}
To avoid bulky code, do all the cell layout in custom cell itself instead of doing it in the delegate or dataSource methods. That will only make you ViewController heavier and non-modular.

How to fix 'tableview cellforrowat not called?'

I'm setting up a tableview with customtableview cell, but when i run the app, the data is not shown.
I already check all the connection, identifier, class name, etc
import UIKit
class ViewController: UITableViewController {
#IBOutlet var testingTableView: UITableView!
var data = ["Indomie","Kacang Tanah","Soya"]
override func viewDidLoad() {
super.viewDidLoad()
testingTableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "customCell")
// Do any additional setup after loading the view.
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = testingTableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! customTableViewCell
cell.customLabel.text = data[indexPath.row]
return cell
}
override func numberOfSections(in tableView: UITableView) -> Int {
return data.count
}
}
This is my code for the table view, it's should call the cellforrowat but it's not
You are missing tableView(_:numberOfRowsInSection:) implementation.
You have number of data.count section, but each section has 0 row.
Try replacing numberOfSections(in:) to tableView(_:numberOfRowsInSection:)
I guess you need additional code as below-
testingTableView.delegate = self
testingTableView.datasource = self
testingTableView.reloadData() // I think you missed it!
1). Add this line
#IBOutlet var testingTableView: UITableView! {
didSet {
testingTableView.delegate = self
testingTableView.dataSource = self
}
}
2). You also can add this feature via Stroyboard. Click on your table and using right click drag the pointer on ViewController and add delegate and dataSource.
And i think you missed
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0 //As per your need.
}
You are using the wrong API, numberOfSections returns the number of sections but you have to return the number of rows
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { {
return data.count
}
There is no need to override numberOfRowsInSection, the default value is 1.
And delete
#IBOutlet var testingTableView: UITableView!
There is an implicit tableView property of UITableViewController

I want to create a signup Form with n number of UITextFields in custom UITableViewCell

I m creating a UITableViewCell which can display n numbers of UITextfields.Please suggest me how to declare these textfields . And also mention how to implement the cellForRowAt function for it.
Heres my UITableViewCell file
import UIKit
class CustomTableViewCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var textlab: UITextField!
func configure(text: String?, placeholder: String) {
textlab.text = text
textlab.placeholder = placeholder
textlab.accessibilityValue = text
textlab.accessibilityLabel = placeholder
}
#IBOutlet weak var underlineLabel: UILabel!
#IBOutlet weak var AlertMessage: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
AND THE VIEW CONTROLLER FOR IT IS AS FOLLOWS:
import UIKit
class CustomViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
var blanklabel = ["","","",""]
var textfields = ["First Name","Last Name","Email","Contact Number"]
var alertmsg = ["Please enter your First Name","Please enter your Last Name","Please enter your Email","Please enter your Contact number",]
var textfield = UITextField()
var AlertMessage = UILabel()
#IBAction func nextLabel(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomTableViewCell
return cell
}
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
return nil
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
}
It's not good idea to do it in UITableView with dynamic cells. Try to use custom view (change your cell class to subclass of UIView) in UIStackView or UITableView with static cells. And set uitextfields as properties in your viewcontroller.