I'm trying to figure out how to do both a custom xib and class for a tableviewcell using Firebase UI
Things I have setup in XCode:
I have a custom xib file called EventCellView.xib and
the custom tableviewcell inside of the xib has a reuse id of eventCell, it is also of the class EventTableViewCell
my code for the EventTableViewCell custom class is
class EventTableViewCell: UITableViewCell {
#IBOutlet weak var eventTitle: UILabel!
#IBOutlet weak var eventDate: UILabel!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() { super.awakeFromNib() }
}
Currently, reading the Firebase UI docs from github I've tried multiple different ways to setup my datasource, this is the one most recent one:
self.dataSource = FirebaseTableViewDataSource(ref:fbRef,
nibNamed: "EventCellView",
cellReuseIdentifier: "eventCell",
view: self.eventTable)
self.dataSource!.populateCellWithBlock { (cell: UITableViewCell, obj: NSObject) -> Void in
let snap = obj as! FDataSnapshot
var customCell = cell as! EventTableViewCell
customCell.eventTitle.text = snap.key
}
Basically per the instructions on Github it says to subclass UITableViewCell and to implement the init (style, resuseId) method, I then specify the cellResuseIdentifier and nib inside of the datasource and I get the following error:
Terminating app due to uncaught exception `NSInternalInconsistencyException`, reason:
invalid nib registered for identifier (eventCell)
- nib must contain exactly one top level object which must be a UITableViewCell instance
Any help would be awesome, thank you.
Related
I create a UITableViewCell subclass CustomTableViewCell and mark it as #IBDesignable. In CustomTableViewCell.xib file I drag a label to its center, then setup an #IBOutlet and name this label as contentLabel. Next, I drag a TableViewCell and put it on a ViewController's table view in the storyboard file, and change its class to CustomTableViewCell. My question is: how to render this contentLabel in the storyboard?
The following snippet doesn't work and I believe it's because contentLabel is not initialized yet in init(), but I want to give it an initial text and render it in the storyboard. How to achieve this?
#IBDesignable class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var contentLabel: UILabel!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentLabel.text = "Hello"
}
required init?(coder: NSCoder) {
super.init(coder: coder)
contentLabel.text = "Hello"
}
}
EDIT: This cell needs to reused in several different view controllers.
When do outlets get bound to a UITableViewCell instance? If I print myLabel in the debugger, it's nil and prints:
fatal error: unexpectedly found nil while unwrapping an Optional value
class MyTableViewCell: UITableViewCell {
#IBOutlet var myLabel: UILabel!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
print("\(myLabel)")
}
}
Outlets are not yet set when the init method of your tableview cell is called!
I'm not sure what your intention is:
If you want to make sure you are not unwrapping a nil optional value just use if let like this:
if let label = myLabel {
print("\(label)")
}
If you want to setup the cell of your tableView, you should first register the cell by calling tableView.registerNib(UINib(nibName: "MyTableViewCell", bundle: nil), forCellReuseIdentifier: "reuse"). Then dequeue the cell in cellForRowAtIndexPath using tableView.dequeueReusableCellWithIdentifier("reuse") and make sure you set the values of your cell in awakeFromNib:
override func awakeFromNib() {
super.awakeFromNib()
//you can be sure that myLabel is initialzed here
print("\(myLabel)")
}
If you are connecting an outlet from the Main Storyboard, your problem could arise if the outlet was accidentally deleted. Recreate the outlet and the label will not be nil anymore.
The issue is that you are running into a case where myLabel is nil. It could be while the table view cell is being recycled.
I have a custom UITableViewCell subclass with a simple IBOutlet setup for a UILabel.
class SegmentCell: UITableViewCell {
#IBOutlet weak var test: UILabel!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
test.text = "Some Text"
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Convinced I have everything set up correct have followed other answers, but the UILabel is always nil.
ViewController:
viewDidLoad:
self.tableView.registerClass(SegmentCell.self, forCellReuseIdentifier: "Cell")
cellForForAtIndexPath
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! SegmentCell
return cell
}
Cell is set to Custom
Reuse identifier is correct
Cells class is SegmentCell
Tableview content is Dynamic Prototypes
What am I missing?
Since You are uisg Xib file you have to register with ,
tableView.register(UINib(nibName: "yourNib", bundle: nil), forCellReuseIdentifier: "CellFromNib")
Think, if only register with class ,system will not know the its Xib.This work for me.
Based on the way you register your cell, it is not going to be loading it from a storyboard or xib file. It will be invoking that init method only. Your init method does not create the label, so it will always be nil.
You should also use dequeueReusableCellWithIdentifier(_:forIndexPath:) instead of dequeueReusableCellWithIdentifier(_:). The latter predates storyboards and will return nil unless you have previously created a cell with that identifier and returned it.
Lastly, the init method that the tableView is calling is not the one you've implemented, or the app would crash on test.text = ... while trying to unwrap a nil optional.
UITableViewCell class and ContentView class can't be same.
You should register it first in the viewDidLoad function.
self.tableView.registerClass(CustomCell.self, forCellReuseIdentifier: "Cell")
I have same issue, after add custom cell class to cell in tableview placed in Storyboard.
I also register cell, like in documentation. But now I solve my issue.
"I remove registering and inspect cell again, all IBOutlets initialised"
I think that basically the outlets are not setup yet at init time. If you want to get to the outlets and manipulate them, then override didMoveToSuperview or similar and do it in there. For instance, this is what I had to do to get to the button outlet in my cell:
open class MyTableViewCell: UITableViewCell {
// Top stack view, not the inner one.
#IBOutlet weak var stackView: UIStackView!
#IBOutlet weak var buttonView: UIButton?
open override func didMoveToSuperview() {
buttonView?.titleLabel?.adjustsFontForContentSizeCategory = true
}
func adjustForAccessibilityCategory(accessible: Bool) {
if accessible {
stackView.axis = .vertical
stackView.alignment = .leading
stackView.spacing = 2
} else {
stackView.axis = .horizontal
stackView.alignment = .center
stackView.spacing = 20
}
}
open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
if #available(iOS 11.0, *) {
adjustForAccessibilityCategory(accessible: traitCollection.preferredContentSizeCategory.isAccessibilityCategory)
}
}
}
I'm trying to use a custom TableViewCell Class in my programmatically created UITableView and i can't figure out why this don't get to work. I've used custom TableViewCell Classes a few times without any problems (set the Classname in Storyboard) but here i have no Storyboard to set the Class which should be used to generate the Cells.
I'm doing this:
override func viewDidLoad() {
...
self.popupTableView.registerClass(CustomTableViewCellPopup.self, forCellReuseIdentifier: "popupTableViewCell")
...
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("popupTableViewCell") as CustomTableViewCellPopup
...
return cell
}
class CustomTableViewCellPopup: UITableViewCell {
var message: UILabel = UILabel()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init(coder decoder: NSCoder) {
super.init(coder: decoder)
}
override func awakeFromNib() {
super.awakeFromNib()
println("I'm running!")
self.message.frame = CGRectMake(0, 0, 10, 10);
self.message.backgroundColor = UIColor.brownColor()
self.addSubview(self.message)
}
}
The println() Output never appears. The TableView gets rendered without the additional UILabel (message). Just like an out of the box UITableViewCell.
The same way (without registerClass()) i'm running a TableView with custom Cells from the Storyboard (the Classname directly defined in the Storyboard Inspector) without any problems.
Have you an idea why the custom Class don't get used?
awakeFromNib won't get called unless the cell is loaded from a xib or storyboard. Move your custom code from awakeFromNib into initWithStyle:reuseIdentifier: because that's the initializer used by the tableView when you call its dequeueReusableCellWithIdentifier: method
You're not seeing the println output because that's in awakeFromNib, which is only called if you cell comes from a storyboard or XIB. Here you're just registering the class with the table, so there's no Nib loading going on. Try making a call to configure the cell from tableView:cellForRowAtIndexPath:, rather than configuring in awakeFromNib.
initWithCoder: won't be called for the same reason - try overriding initWithStyle:reuseIdentifier:.
I am trying to create a custom tableview cell in interface builder and use it in a tableview created in swift, the relevant code in the controller holding the tableview is as fallows:
class SearchesMainViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var contentTableView: UITableView?
override func viewDidLoad(){
super.viewDidLoad()
self.navigationItem.title = "Search"
self.contentTableView?.registerNib(UINib(nibName: "SingleSearchTableViewCell", bundle: nil), forCellReuseIdentifier: SingleSearchTableViewCellController.reuseID())
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
var cell = tableView.dequeueReusableCellWithIdentifier(SingleSearchTableViewCellController.reuseID(), forIndexPath: indexPath) as SingleSearchTableViewCellController
return cell
}
The Cell itself is very simple, 4 labels and a custom class:
class SingleSearchTableViewCellController : UITableViewCell {
#IBOutlet var dateMonthLable : UILabel?
#IBOutlet var dateDayLable : UILabel?
#IBOutlet var yearLable : UILabel?
#IBOutlet var makeModelLable : UILabel?
var search : Search
class func reuseID() -> String{
return "SingleSearchTableViewCellType"
}
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
search = Search()
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
required init(coder aDecoder: NSCoder) {
search = Search()
super.init()
}
init(previousSearch s : Search){
search = s
super.init()
}
override init(frame: CGRect) {
search = Search()
super.init(frame: frame)
}
If I did not put enough data please feel free to ask and I thank you for your help in advance. Info on swift interacting with xib does not seem to be widely available yet.
EDIT
I have removed my custom class and the bindings for my cell look like this:
after making these changes the error reads as fallows:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key dateDayLable.'
now it looks like it is trying to bind my views to some view that is not my customUITableViewCellController
When I run into these kinds of issues it usually is caused by two things. One is that the main view in the xib file is a UIView instead of a UITableViewCell. The other is that the custom class field isn't being set to your custom class.
Check your "Datasource" and "Delegate" connections.
Check that you have added to viewController.
Check that you have properly assigned "dequeueReusableCellWithIdentifier".