TableView Inside a UITableViewCell - must register a nib or class - ios

I'm putting a UITableView inside UITableViewCell.
I've extended my class of UITableViewCell to ,UITableViewDataSource, UITableViewDelegate.
Made the #IBOutlet var tableView: UITableView!
Added the following:
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style , reuseIdentifier: reuseIdentifier)
setUpTable()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
setUpTable()
}
override func awakeFromNib() {
super.awakeFromNib()
setUpTable()
}
Where as setUpTable() is implemented as:
func setUpTable(){
tableView?.delegate = self
tableView?.dataSource = self
//tableView.register(UINib(nibName: "AvailableTimingsTableViewCell", bundle: nil), forCellReuseIdentifier: "TimingCell")
}
If I keep the commented line in setUpTable() I get:
'unable to dequeue a cell with identifier TimingCell - must register a
nib or a class for the identifier or connect a prototype cell in a
storyboard'
If I uncomment the comment I get:
fatal error: unexpectedly found nil while unwrapping an Optional value
on the same line.
After setUpTable() I've implemented them as:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TimingCell", for: indexPath) as?AvailableTimingsTableViewCell
cell?.dayNameLabel.text = "Wednesday"
cell?.timeLabel.text = "01:00 PM - 03:00 PM"
return (cell)!
}
EDIT Here are the screenshots of the class names. I've double checked all is okay as per the comments and answer.

I think that setUpTable() in the init() is called too soon. At that point view is not loaded. Do that setup in viewDidLoad(), also don't comment out registering the cell. Other than that code looks good.

Please check Below points
1) You need to register cell identifier in XIB,
2) Assign Class name to XIB
3) cell for row you need to check with as? YourClass in dequeue and
4) dequeue with same identifier you assign to XIB and register (Here is issue as per me )

Related

Set data in UITableViewCell

I try use UITableViewCell. My custom cell has StackView's and other views.
I need to send object from controller (UITableViewController) for next parsing it.
in cell I set field:
class MyCell: UITableViewCell {
var myObject : MyObject?
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
in this I try get data from my object
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
and in my Controller I write:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// create a new cell if needed or reuse an old one
let cell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as MyCustomCell!
cell.myObject = self.arrayMyObjects[indexPath.row]
return cell
}
But everytime I have nil in my cell. Why?
In your cell init is to early to try and access myObject. You should use a didSet on the property to make the changes when it's assigned a new value.
var myObject : MyObject? {
didSet {
// Update your subviews here.
}
}

How to Custom UITableViewCell in swift

I'm a newbie in swift, and i try to custom UITableViewCell, i see many tutorial in youtube and internet. But i can't do it, i tried to fix a lot of way but nothing is change.
here is my code :
class movieViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
var categories = ["Action", "Drama", "Science Fiction", "Kids", "Horror"]
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var btnMenu: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
btnMenu.target = self.revealViewController()
btnMenu.action = Selector("revealToggle:")
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
self.revealViewController().rearViewRevealWidth = 200
self.tableView.registerClass(CategoryRow.self, forCellReuseIdentifier: "Cell")
// Do any additional setup after loading the view.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return categories[section]
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return categories.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CategoryRow
cell.labelA.text = self.categories[indexPath.row]
cell.labelB.text = self.categories[indexPath.row]
return cell
}
CategoryRow.swift:
class CategoryRow: UITableViewCell {
var labelA: UILabel!
var labelB: 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
}
}
and my bug :
It seem that you don't have xib. And you just declare your label but you don't init it. So labelA and labelB will nil. it make crash.
If you don't want xib, You must implement two function in CategoryRow like code below:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.labelA = UILabel(frame: CGRectMake(0,0, self.contentView.frame.size.width, self.contentView.frame.size.height))
//Same here for labelB
self.contentView.addSubview(labelA)
}
Another way is you create xib UITableCiewCell with name same with your class. And set this cell is your class. You design labelA and labelB in this xib and drage outlet into class. And you modify in viewDidLoad
self.tableView.registerNib(UINib(nibName: "nameYourxib"), forCellReuseIdentifier: "Cell")
You haven't linked labelA inStoryboard.
Creating an Outlet Connection
You have not allocate the labelA or labelB. Thats why show the error. Connect your label with you UI like this:
#vien vu answer is right but what to do without XIB ?? Here is the complete solution for Custom cell in swift
You need to add delegate a datasource in viewDidLoad
viewDidLoad() {
self.tableView.delegate = self
self.tableView.datasource = self
}
and you need to create the labelA and labelB by outlets not variables. Hold control and drag from Storyboard to the corisponding file and let go, choose outlet and give it the name labelA and labelB

Empty Cells in TableView with Custom TableViewCell - Swift

I am currently learning Swift programatically. I am wanting to add a tableView to a viewController (for the purpose of being able to manipulate the constraints later) and customize the cells with a TableViewCell.
I can do this with my eyes closed when using the storyboard, but when I try to do it with just straight code I have empty cells.
My storyboard is comprised of one (1) empty viewController that has the custom class of ViewController
I have looked at others with similar issues but non of the solutions have worked. Would love to know what I am overlooking (probably something simple). Thanks in advance for the help!
ViewController.swift:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
var tableView: UITableView = UITableView()
var items: [String] = ["Viper", "X", "Games"]
override func viewDidLoad() {
tableView.frame = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height)
tableView.delegate = self
tableView.dataSource = self
tableView.registerClass(TableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(tableView)
}
func tableView(tableView:UITableView, heightForRowAtIndexPath indexPath:NSIndexPath)->CGFloat
{
return 50
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.items.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableViewCell
//cell.textLabel?.text = self.items[indexPath.row]
cell.companyName.text = "name"
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
TableViewCell:
import UIKit
class TableViewCell: UITableViewCell {
var companyName = UILabel()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
companyName.frame = CGRectMake(0, 0, 200, 20)
companyName.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(companyName)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Hello #Michael First thing is you should only use awakeFromNib when you are using a .xib(Nib) and in your case you are using custom class without such xib so, you should use
override init(style: UITableViewCellStyle, reuseIdentifier: String?){
super.init(style: style, reuseIdentifier: reuseIdentifier)
companyName = UILabel(frame: CGRectMake(0, 0, 200, 20))
contentView.addSubview(companyName)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
also you should initialise your label before using it.
this will solve your problem.
Read apple's documentation for subclassing UITableViewCell here.
If you want your custom cell to load from some custom xib you do sometimes like:
tableView.registerNib(UINib(nibName: "CustomTableViewCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: "CustomTableViewCell")
And you should have CustomTableViewCell.xib file where you have table view cell with reuse identifier CustomTableViewCell
Checkout how your cell's companyLabel is laid out. Does it exist or no?
In your code, I replaced companyLabel with default textLabel and it worked for me.
cell.textLabel!.text = self.items[indexPath.row]
I think awakeFromNib is not called because you do not register a nib but a class. Try this instead:
class TableViewCell: UITableViewCell {
let companyName = UILabel()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// Initialization code
companyName.frame = CGRectMake(0, 0, 200, 20)
companyName.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(companyName)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}

Swift Custom UITableViewCell Programmatically works and shows in cell but Storyboard IBOutlet is nil and does not show in cell

In my custom cell swift file CustomTableView.swift, I can create programmatically the labels for my TableView but when I use IBOutlet in Storyboard the label becomes always nil
I am very sure that my cell is not nil
import UIKit
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var lblPostDate: UILabel!
var message: UILabel = UILabel()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.message.frame = CGRectMake(0, 0, 100, 40);
self.message.backgroundColor = UIColor.brownColor()
self.message.text = "bla bla bla bla bla"
self.addSubview(self.message)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
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
}
func setCell(postDate: String)
{
self.lblPostDate?.text = postDate
}
}
In the above code, the message can be seen in the cells but lblPostDate which is the IBOutlet can not be seen
I am sure about the delegate and datasource and custom cell identifier what so ever but it seems that the IBOutlets don't get initialized correctly. I can see that lblPostDate becomes nil when I debug
Is this a bug of XCode 6?
Here is how I call from my Controller
import UIKit
class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var items = ["one","two","three","four"]
let kCellIdentifier: String = "CustomCell"
#IBOutlet weak var mTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.mTableView.registerClass(CustomTableViewCell.classForCoder(), forCellReuseIdentifier:kCellIdentifier)
//self.mTableView.registerClass(CustomTableViewCell.self, forCellReuseIdentifier: kCellIdentifier)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:CustomTableViewCell! = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier, forIndexPath: indexPath) as? CustomTableViewCell
if (cell == nil) {
self.mTableView.registerClass(CustomTableViewCell.classForCoder(), forCellReuseIdentifier: kCellIdentifier)
cell = CustomTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: kCellIdentifier)
}
if var label = cell.lblPostDate{
label.text = items[indexPath.row]
}
else{
cell.setCell(items[indexPath.row])
}
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 44
}
}
You have to link the lblPostDate with one label in your cell xib file.
That is insane, I deleted the register class code and it worked, I can't believe it
//self.mTableView.registerClass(CustomTableViewCell.classForCoder(), forCellReuseIdentifier:kCellIdentifier)
After commenting out the registerClass in my Controller, it doesn't call anymore the init function but creates the lblPostDate correctly indeed
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.message.frame = CGRectMake(0, 0, 100, 40);
self.message.backgroundColor = UIColor.brownColor()
self.message.text = "bla bla bla bla bla"
self.addSubview(self.message)
}
So I don't need anymore to create hard-code input objects.
It is interesting that all the tutorials, everywhere they suggest to register the class. Anyway,it worked!

Custom UITableViewCell in Swift programmatically

I'm looking to programmatically create a UITableView and corresponding custom UITableViewCell in Swift. The table view is working great, but it doesn't seem like the cell labels are instantiating - they come back as nil.
I also don't know how to refer to the content view size when sizing elements.
UITableViewCell
import UIKit
class BusUITableViewCell: UITableViewCell {
var routeNumber: UILabel!
var routeName: 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
routeName = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 50)) // not sure how to refer to the cell size here
contentView.addSubview(routeNumber)
contentView.addSubview(routeName)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
UITableView delegate and source
import Foundation
import UIKit
class BusUITableView: NSObject, UITableViewDelegate, UITableViewDataSource {
var routeService: RouteService = RouteService()
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var busRoutes: [Route] = routeService.retrieve()
return busRoutes.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:BusUITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell") as BusUITableViewCell
var busRoutes: [Route] = routeService.retrieve()
cell.routeName.text = "test" // test string doesn't work, returns nil
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
}
View Controller
mainTableView.registerClass(BusUITableViewCell.self, forCellReuseIdentifier: "cell")
If you aren't linking to a prototype cell in a storyboard then you need to register the class for your cell against your tableView using registerClass(_ cellClass: AnyClass,
forCellReuseIdentifier identifier: String)
In your case you would use something like this
tableview.register(BusUITableViewCell.self, forCellReuseIdentifier:"cell")
Also, without a NIB file, awakeFromNib won't be invoked.
Edit: .registerClass() has been renamed to .register()
Considering you are doing this "programmatically" (no nib file), you're awakeFromNib() will never invoke. You can create a nib, and link it to this backing file, and still create and use the cell programmatically. Or ... choose a different place (like the initializer) to create and add subviews to the cell.

Resources