I have a UITableView on the ViewController. Here is complete code
import UIKit
class UnitTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var unitTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.unitTable.register(UnitCell.self, forCellReuseIdentifier: "UnitCell")
self.unitTable.delegate = self
self.unitTable.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = unitTable.dequeueReusableCell(withIdentifier: "UnitCell", for: indexPath) as! UnitCell
cell.unitNameLbl?.text = "TEST"
return cell
}
}
But unfortunately my custom cell is not visible. I've put green background colour to be sure that constraints are right.
Here is my UnitCell code
import UIKit
class UnitCell: UITableViewCell {
#IBOutlet weak var unitNameLbl: UILabel?
#IBOutlet weak var unitNumberLbl: 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
}
}
What could be wrong if I can't see my custom cell?
try this following into viewDidLoad
unitTable.register(UINib(nibName: "yourCellClassName", bundle: nil), forCellReuseIdentifier: "UnitCell")
You can't directly use class name of cell because you'r using XIB of cell so you must need to register cell with nib name like below.
let nib = UINib(nibName: "YourTableViewCellNibName", bundle: nil)
self.unitTable.register(nib, forCellReuseIdentifier: "UnitCell")
change registering cell to table code as below.
override func viewDidLoad() {
super.viewDidLoad()
self.unitTable.register(UINib(nibName: "UnitTable", bundle: nil), forCellReuseIdentifier: "UnitCell") // nibName should be exact name of xib file of your custom cell.
self.unitTable.delegate = self
self.unitTable.dataSource = self
}
I get an error by the IBoutlet of tableView saying "cannot override with stored property "tableView"". I'm not quite sure what this means, any type of help will be appreciated.
import UIKit
class UsersViewController: UITableViewController {
#IBOutlet var tableView: UITableView!
var users = ["Marc", "Mark" , "Louise", "Ahinga", "Amossi", "Kalenga"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView:UITableView, numberOfRowsInSection section:Int) -> Int {
return 3
}
override func tableView(tableView:UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! userCell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
}
A UITableViewController comes with a UITableView built in, aptly named tableView. In the code you pasted you are adding an extra UITableView to it and giving it the same name. That's what the compiler is complaining about.
In theory, when you are using a plain vanilla UITableViewController from the storyboard you should not link the table to an IBOutlet. That's taken care of.
If you are building something more sophisticated that needs an extra UITableViewController on top of the one that the class provides in storyboard, then you should name it differently.
you have to set as it's delegate and dataSource in viewDidLoad() like this
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
}
I want to create a page which should have a map on the top and 5 row tableview at the bottom. So i created UIViewController put my Map View then put TableView. I created myViewController.swift and myTableViewCell.swift
But when i try on simulator no data showing on tableview. Only empty cells.I received no error
Here is my code. Thank you
import UIKit
import MapKit
class myViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var mapView: MKMapView!
var labels = ["some arrays"]
var images = ["some image names in an array"]
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return labels.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("mySegue", forIndexPath: indexPath) as! myTableViewCell
cell.myCellLabel.text = labels[indexPath.row]
cell.myCellImage.image = UIImage(named: images[indexPath.row])
return cell
}
}
try this:
override func viewDidLoad() {
super.viewDidLoad()
// Add this
tableView.delegate = self
tableView.dataSource = self
}
You should do one out of two way :
tableView.delegate = self
tableView.dataSource = self
in the viewDidLoad() of your viewController
OR
- select the tableView and dragging by pressing control to viewController, first select the datasource and again doing so select the delegate.
Assign delegate and datasource of UITableView/ UICollectionView through storyboard to reduce code as follows:
Right click on your UITableView, then click on round circle for Delegate/ Datasource and move on to the viewcontroller. For clarity, see the image below.
Set the dataSource of the tableview.
tableview.dataSource = self
tableview.delegate = self
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'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)
}