I am new to iOS development.
I'm trying to display a list of items in my app using UITableView, but the items are not showing:
My View Controller:
class HistoryView: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
let cellReuseIdentifier = "cell"
#IBOutlet weak var noDataLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(HistoryTableViewCell.self, forCellReuseIdentifier: "historyCell")
tableView.delegate = self
tableView.dataSource = self
self.noDataLabel.isHidden=true
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "historyCell") as! HistoryTableViewCell
cell.nickname?.text = "name"
return cell
}
}
My Table View Cell:
class HistoryTableViewCell: UITableViewCell {
#IBOutlet weak var nickname: 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
}
}
Any suggestions for what's going on?
condition 1:
if you are using prototype cells remove the line
tableView.register(HistoryTableViewCell.self, forCellReuseIdentifier:"historyCell")
and give cell identifier in the storyboard
condition 2:
if you are using xib file then register the cell like below:-
tableView.register(UINib(nibName: "HistoryTableViewCell", bundle: nil), forCellReuseIdentifier: "historyCell")
you need to register cell like this
tb.register(UINib(nibName: "HistoryTableViewCell", bundle: nil), forCellReuseIdentifier: "historyCell")
I saw #IBOutlet weak var nickname: UILabel!
in the class HistoryTableViewCell.
for table cells,
dequeueReusableCell and register, should called in pairs
var leadername = ["1","2","3","4"]
var districts = ["Delhi","Kerala"]
override func viewDidLoad() {
leadTableSetup()
super.viewDidLoad()
}
func leadTableSetup(){
LeadTableView.delegate = self
LeadTableView.dataSource = self
self.LeadTableView.register(UINib(nibName: "LeaderBoardTableViewCell", bundle: nil), forCellReuseIdentifier: "leadCell")
}
func numberOfSections(in tableView: UITableView) -> Int {
return 5
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 14
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "leadCell") as! LeaderBoardTableViewCell
// Set text from the data model
cell.areaLbl.text = districts[indexPath.row]
cell.leaderNameLbl.text = leadername[indexPath.row]
return cell
}
I have declared two strings and I need to display these strings in the labels in my custom collection view cell that I have created. How can I achieve this? I need to display "leadername" string in one label and "districts" label in another label.
Go with this demo, Shared Demo
After the demo, If you still face any problem then let me know.
Now Listen Here
I think you need output something like this,
Follow the steps: -
Create a new viewcontroller(says, CustomTableVC) in your storyboard and one UITableView(give constraints and delegate to its own class), take outlet of UItableView (says, tblMyCustom)
Now press CLT+N for new file and do like this below image, Subclass - UItableViewCell and also tick on XIB option.
Open our xib file, add new UIView (says myView, as you see highted in below image), in this myView add two labels
Now take outlet of these two labels in its customCell class
class CustomTableCell: UITableViewCell {
#IBOutlet var lblLeaderNo: UILabel!
#IBOutlet var lblDistict: 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
}
}
Now back to your Viewcontroller Class
import UIKit
class CustomTableVC: UIViewController , UITableViewDelegate, UITableViewDataSource{
#IBOutlet var tblMyCustom: UITableView!
var leaderno : [String]!
var distict : [String]!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.tblMyCustom.register(UINib(nibName: "CustomTableCell", bundle: nil), forCellReuseIdentifier: "customCell")
self.leaderno = ["1", "2", "3", "4"]
self.distict = ["Delhi","Kerala", "Haryana", "Punjab"]
// above both array must have same count otherwise, label text in null
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return leaderno.count;
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
var customCell: CustomTableCell! = tableView.dequeueReusableCell(withIdentifier: "customCell") as? CustomTableCell
customCell.lblLeaderNo.text = self.leaderno[indexPath.row]
customCell.lblDistict.text = self.distict[indexPath.row]
return customCell
}
}
above all is code of VC, it is not getting settle down here in single code format, I dont know why.
Now, follow these steps you get output as i show you image in starting of the procedure.
I have created a custom UITableView cell in my Storyboard that looks like this:
I hooked it up to my UITableViewCell class like this:
import UIKit
class StatusCell: UITableViewCell {
#IBOutlet weak var InstrumentImage: UIImageView!
#IBOutlet weak var InstrumentType: UILabel!
#IBOutlet weak var InstrumentValue: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Finally I attempted to initialize the UITableView from my UIViewController as such:
import UIKit
class SecondViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var TableView: UITableView!
let Items = ["Altitude","Distance","Groundspeed"]
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.Items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: StatusCell! = tableView.dequeueReusableCellWithIdentifier("Cell") as StatusCell!
cell.InstrumentType?.text = Items[indexPath.row]
cell.InstrumentValue?.text = "150 Km"
cell.InstrumentImage?.image = UIImage(named: Items[indexPath.row])
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
However, when I attempt to run the program I get an EXC_BAD_INSTRUCTION error:
What could I have done wrong? Any help would be appreciated!
The debugger output shows that cell is nil, meaning it could not be instantiated. Furthermore, you are forcing an unwrapping of the optional (using the !) which causes the app to crash on the nil value.
Try to change your cellForRowAtIndexPath method like so (notice the dequeueReusableCellWithIdentifier method):
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as StatusCell
cell.InstrumentType.text = Items[indexPath.row]
cell.InstrumentValue.text = "150 Km"
cell.InstrumentImage.image = UIImage(named: Items[indexPath.row])
return cell
}
Assuming that your custom tableViewCell class is correctly set up and the outlets are bound, there is no need to check for optionals.
Place a breakpoint on the let cell = ... line and step through the code. Check if cell gets initialized and is not nil.
And please: Do not use upper case names for properties and variables (your outlets, Items array...) as upper case names are for classes, structs, ...
I used custom UITableViewCell named "SCTableViewCell" and linked with "CustomCell.xib" and loading in "CenterViewController"
and when it runs, several cells on the top looks bad(like follow picture) and, after scroll down screen and up again(bad cells once disappear and appear again) it looks fine
it is custom cell class
SCTableViewCell.swift
class SCTableViewCell: UITableViewCell {
#IBOutlet weak var thumbnailImage : UIImageView!
#IBOutlet weak var titleLabel : UILabel!
#IBOutlet weak var descLabel : UILabel!
func loadItem(#title: String, desc: String, image: UIImage){
titleLabel.text = title
descLabel.text = desc
thumbnailImage.image = image
self.contentView.setTranslatesAutoresizingMaskIntoConstraints(true)
}
override func layoutSubviews() {
}
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
}
}
and CenterViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
//Setting Custom Tableview Cell
self.tableView.registerNib(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell", forIndexPath: indexPath) as SCTableViewCell
cell.loadItem(title: title!, desc: desc!, image: pic)
cell.updateConstraints()
return cell
}
console shows nothing....
please help me...
Oh!
I didn`t set up my cell height... ha...ha....
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 160
}
added in CenterViewController.swift and it works
I'm trying to create a custom table view cell from a nib. I'm referring to this article here. I'm facing two issues.
I created a .xib file with a UITableViewCell object dragged on to it. I created a subclass of UITableViewCell and set it as the cell's class and Cell as the reusable identifier.
import UIKit
class CustomOneCell: UITableViewCell {
#IBOutlet weak var middleLabel: UILabel!
#IBOutlet weak var leftLabel: UILabel!
#IBOutlet weak var rightLabel: UILabel!
required init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
}
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
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
}
}
In the UITableViewController I have this code,
import UIKit
class ViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {
var items = ["Item 1", "Item2", "Item3", "Item4"]
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - UITableViewDataSource
override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let identifier = "Cell"
var cell: CustomOneCell! = tableView.dequeueReusableCellWithIdentifier(identifier) as? CustomOneCell
if cell == nil {
tableView.registerNib(UINib(nibName: "CustomCellOne", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCellWithIdentifier(identifier) as? CustomOneCell
}
return cell
}
}
This code complies with no errors but when I run it in the simulator, it looks like this.
In the UITableViewController in the storyboard I haven't done anything to the cell. Blank identifier and no subclass. I tried adding the Cell identifier to the prototype cell and ran it again but I get the same result.
Another error I faced is, when I tried to implement the following method in the UITableViewController.
override func tableView(tableView: UITableView!, willDisplayCell cell: CustomOneCell!, forRowAtIndexPath indexPath: NSIndexPath!) {
cell.middleLabel.text = items[indexPath.row]
cell.leftLabel.text = items[indexPath.row]
cell.rightLabel.text = items[indexPath.row]
}
As shown in the article I mentioned I changed the cell parameter's type form UITableViewCell to CustomOneCell which is my subclass of UITableViewCell. But I get the following error,
Overriding method with selector 'tableView:willDisplayCell:forRowAtIndexPath:' has incompatible type '(UITableView!, CustomOneCell!, NSIndexPath!) -> ()'
Anyone have any idea how to resolve these errors? These seemed to work fine in Objective-C.
Thank you.
EDIT: I just noticed if I change the simulator's orientation to landscape and turn it back to portrait, the cells appear! I still couldn't figure out what's going on. I uploaded an Xcode project here demonstrating the problem if you have time for a quick look.
With Swift 5 and iOS 12.2, you should try the following code in order to solve your problem:
CustomCell.swift
import UIKit
class CustomCell: UITableViewCell {
// Link those IBOutlets with the UILabels in your .XIB file
#IBOutlet weak var middleLabel: UILabel!
#IBOutlet weak var leftLabel: UILabel!
#IBOutlet weak var rightLabel: UILabel!
}
TableViewController.swift
import UIKit
class TableViewController: UITableViewController {
let items = ["Item 1", "Item2", "Item3", "Item4"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
}
// MARK: - UITableViewDataSource
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.middleLabel.text = items[indexPath.row]
cell.leftLabel.text = items[indexPath.row]
cell.rightLabel.text = items[indexPath.row]
return cell
}
}
The image below shows a set of constraints that work with the provided code without any constraints ambiguity message from Xcode:
Here's my approach using Swift 2 and Xcode 7.3. This example will use a single ViewController to load two .xib files -- one for a UITableView and one for the UITableCellView.
For this example you can drop a UITableView right into an empty TableNib.xib file. Inside, set the file's owner to your ViewController class and use an outlet to reference the tableView.
and
Now, in your view controller, you can delegate the tableView as you normally would, like so
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
...
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Table view delegate
self.tableView.delegate = self
self.tableView.dataSource = self
...
To create your Custom cell, again, drop a Table View Cell object into an empty TableCellNib.xib file. This time, in the cell .xib file you don't have to specify an "owner" but you do need to specify a Custom Class and an identifier like "TableCellId"
Create your subclass with whatever outlets you need like so
class TableCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
}
Finally... back in your View Controller, you can load and display the entire thing like so
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// First load table nib
let bundle = NSBundle(forClass: self.dynamicType)
let tableNib = UINib(nibName: "TableNib", bundle: bundle)
let tableNibView = tableNib.instantiateWithOwner(self, options: nil)[0] as! UIView
// Then delegate the TableView
self.tableView.delegate = self
self.tableView.dataSource = self
// Set resizable table bounds
self.tableView.frame = self.view.bounds
self.tableView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
// Register table cell class from nib
let cellNib = UINib(nibName: "TableCellNib", bundle: bundle)
self.tableView.registerNib(cellNib, forCellReuseIdentifier: self.tableCellId)
// Display table with custom cells
self.view.addSubview(tableNibView)
}
The code shows how you can simply load and display a nib file (the table), and second how to register a nib for cell use.
Hope this helps!!!
Swift 4
Register Nib
override func viewDidLoad() {
super.viewDidLoad()
tblMissions.register(UINib(nibName: "MissionCell", bundle: nil), forCellReuseIdentifier: "MissionCell")
}
In TableView DataSource
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "MissionCell", for: indexPath) as? MissionCell else { return UITableViewCell() }
return cell
}
Detailed Solution with Screenshots
Create an empty user interface file and name it MyCustomCell.xib.
Add a UITableViewCell as the root of your xib file and any other visual components you want.
Create a cocoa touch class file with class name MyCustomCell as a subclass of UITableViewCell.
Set the custom class and reuse identifier for your custom table view cell.
Open the assistant editor and ctrl+drag to create outlets for your visual components.
Configure a UIViewController to use your custom cell.
class MyViewController: UIViewController {
#IBOutlet weak var myTable: UITableView!
override func viewDidLoad {
super.viewDidLoad()
let nib = UINib(nibName: "MyCustomCell", bundle: nil)
myTable.register(nib, forCellReuseIdentifier: "MyCustomCell")
myTable.dataSource = self
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "MyCustomCell") as? MyCustomCell {
cell.myLabel.text = "Hello world."
return cell
}
...
}
}
swift 4.1.2
xib.
Create ImageCell2.swift
Step 1
import UIKit
class ImageCell2: UITableViewCell {
#IBOutlet weak var imgBookLogo: UIImageView!
#IBOutlet weak var lblTitle: UILabel!
#IBOutlet weak var lblPublisher: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
step 2 . According Viewcontroller class
import UIKit
class ImageListVC: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var tblMainVC: UITableView!
var arrBook : [BookItem] = [BookItem]()
override func viewDidLoad() {
super.viewDidLoad()
//Regester Cell
self.tblMainVC.register(UINib.init(nibName: "ImageCell2", bundle: nil), forCellReuseIdentifier: "ImageCell2")
// Response Call adn Disply Record
APIManagerData._APIManagerInstance.getAPIBook { (itemInstance) in
self.arrBook = itemInstance.arrItem!
self.tblMainVC.reloadData()
}
}
//MARK: DataSource & delegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.arrBook.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// [enter image description here][2]
let cell = tableView.dequeueReusableCell(withIdentifier: "ImageCell2") as! ImageCell2
cell.lblTitle.text = self.arrBook[indexPath.row].title
cell.lblPublisher.text = self.arrBook[indexPath.row].publisher
if let authors = self.arrBook[indexPath.row].author {
for item in authors{
print(" item \(item)")
}
}
let url = self.arrBook[indexPath.row].imageURL
if url == nil {
cell.imgBookLogo.kf.setImage(with: URL.init(string: ""), placeholder: UIImage.init(named: "download.jpeg"))
}
else{
cell.imgBookLogo.kf.setImage(with: URL(string: url!)!, placeholder: UIImage.init(named: "download.jpeg"))
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 90
}
}
You did not register your nib as below:
tableView.registerNib(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
Another method that may work for you (it's how I do it) is registering a class.
Assume you create a custom tableView like the following:
class UICustomTableViewCell: UITableViewCell {...}
You can then register this cell in whatever UITableViewController you will be displaying it in with "registerClass":
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(UICustomTableViewCell.self, forCellReuseIdentifier: "UICustomTableViewCellIdentifier")
}
And you can call it as you would expect in the cell for row method:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UICustomTableViewCellIdentifier", forIndexPath: indexPath) as! UICustomTableViewCell
return cell
}
For fix the "Overriding method... has incompatible type..." error I've changed the function declaration to
override func tableView(tableView: (UITableView!),
cellForRowAtIndexPath indexPath: (NSIndexPath!))
-> UITableViewCell {...}
(was -> UITableViewCell! -- with exclamation mark at the end)
I had to make sure that when creating the outlet to specify that I was hooking to the cell, not the object's owner. When the menu appears to name it you have to select it in the 'object' dropdown menu. Of course you must declare the cell as your class too, not just 'TableViewCellClass'. Otherwise I would keep getting the class not key compliant.
Simple take a xib with class UITableViewCell. Set the UI as per reuirement and assign IBOutlet. Use it in cellForRowAt() of table view like this:
//MARK: - table method
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.arrayFruit.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:simpleTableViewCell? = tableView.dequeueReusableCell(withIdentifier:"simpleTableViewCell") as? simpleTableViewCell
if cell == nil{
tableView.register(UINib.init(nibName: "simpleTableViewCell", bundle: nil), forCellReuseIdentifier: "simpleTableViewCell")
let arrNib:Array = Bundle.main.loadNibNamed("simpleTableViewCell",owner: self, options: nil)!
cell = arrNib.first as? simpleTableViewCell
}
cell?.labelName.text = self.arrayFruit[indexPath.row]
cell?.imageViewFruit.image = UIImage (named: "fruit_img")
return cell!
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 100.0
}
100% working without any issue (Tested)
This line add in TableView cell:
static var nib : UINib{
return UINib(nibName: identifier, bundle: nil)
}
static var identifier : String{
return String(describing: self)
}
And register in viewcontroller like
This line use in viewDidLoad
tableview.register(TopDealLikedTableViewCell.nib, forCellReuseIdentifier: TopDealLikedTableViewCell.identifier)
cell for row at indexpath
if let cell = tableView.dequeueReusableCell(withIdentifier:
TopDealLikedTableViewCell.identifier) as? TopDealLikedTableViewCell{
return cell
}
return UITableViewCell()
Set on cell
static var identifier : String {
return String(describing: self)
}
static var nib : UINib {
return UINib(nibName: identifier, bundle: nil)
}