I am using xib file to create a custom cell. The reuse identifier is set up in the xib file. Then I have a lazy var that I use to register the nib only once:
private lazy var registerNib: Bool = {
let nib = UINib(nibName: "CustomTableViewCell", bundle: nil)
self.tableView.register(nib, forCellReuseIdentifier: "Custom")
return true
}()
During Cell Creating I just used the lazy var and dequeue the cell from the table view, using the same reuse identifier that I have in the xib file:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let _ = self.registerNib
let cell = tableView.dequeueReusableCell(withIdentifier: "Custom") as! CustomCell
return cell
}
But the unwrapping fails and the app crashes.
tableView.dequeueReusableCell returns nil
for some reason....
There are two methods named dequeueReusableCell.
dequeueReusableCell(withIdentifier:)
dequeueReusableCell(withIdentifier:for:)
But the unwrapping fails and the app crashes. tableView.dequeueReusableCell returns nil for some reason....
You are using the first one and the doc clearly says
Return Value
A UITableViewCell object with the associated identifier or nil if no such object exists in the reusable-cell queue.
You may want to use the latter.
Change the line:
let cell = tableView.dequeueReusableCell(withIdentifier: "Custom") as! CustomCell
To:
let cell = tableView.dequeueReusableCell(withIdentifier: "Custom", for: indexPath) as! CustomCell
You need to register your nib object in viewDidLoad(): method like this
let nib = UINib(nibName: "CustomTableViewCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "Custom")
Also, did you set the cell reuse identifier in the storyboard?
Related
I have two tableviews with two different custom tableview cells.. and am doing this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == self.tableview {
let cell = tableview.dequeueReusableCell(withIdentifier: "matchescell") as! MatchesTableViewCell
// ......
return cell
} else {
let cell = tableview.dequeueReusableCell(withIdentifier: "filtercell") as! FilterTableViewCell
// ......
return cell
}
}
and of course i have registered them both from storyboard...
but i keep getting this:
on this line:
let cell = tableview.dequeueReusableCell(withIdentifier: "filtercell") as! FilterTableViewCell
tried to register them like this:
tableview.register(MatchesTableViewCell.self, forCellReuseIdentifier: "matchescell")
filterdrop.register(FilterTableViewCell.self, forCellReuseIdentifier: "filtercell")
but still getting the same error!
What am doing wrong?!
The problem is that you typed "tableview" instead of "tableView" in your else part:
replace :
let cell = tableview.dequeueReusableCell(withIdentifier: "filtercell") as! FilterTableViewCell
with :
let cell = tableView.dequeueReusableCell(withIdentifier: "filtercell") as! FilterTableViewCell
It is crashing because your "tableview" doesn't have this cell registered.
Add the "filtercell" identifier in the storyboard or xib custom cell (FilterTableViewCell).
Possible cause:
You haven't registered the class or the nib of the cell to the proper tableview
You haven't set the identifier in the cellview in you nib/storyboard
You have inverted the tableview and their cell type
This because you either didn't register the cell
tableView.register(CustomCellClass.self, forCellReuseIdentifier: "CellID")
//
tableView.register(UINib(nibName: "CustomCellClass", bundle: nil), forCellReuseIdentifier: "CellID")
or you swapped the dequeuing line for the tables
Have a look into your Tableview controller in the Storyboard. You should have another indentier than called in:
let cell = tableview.dequeueReusableCell(withIdentifier: "filtercell") as! FilterTableViewCell
BTW, you should always use this newer function
dequeueReusableCell(withIdentifier:for:)
instead of
dequeueReusableCell(withIdentifier:)
See this post for details.
You can easily solve this problem just to check what tableview you use at that time.
you can try this code,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) {
if (tableview == (yourtableview 1)) {
let cell = yourtableview 1.dequeueReusableCell(withIdentifier: "yourtableview Cell 1") as? yourtableview Cell 1
// write your code for tableview 1
return cell
}
else
{
let cell = yourtableview 2.dequeueReusableCell(withIdentifier: "yourtableview Cell 2") as? yourtableview Cell 2
// write your code for tableview 2
return cell
}
}
I am trying to register UITableViewCell in viewdidload
self.tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")
In cellForRowAtIndex
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell") as! CustomTableViewCell
cell.productNameLabel.text = "Product"
cell.productNameLabel.textColor = UIColor.darkGray
return cell
}
Here it is crashing in cell.productNameLabel.text.
What is the purpose of registering cell? why it is crashing?
I want to reload data even if cell or table is not visible.
Crashreport :
See the Apple's comments which answers your query on the purpose of registering cell :
Prior to dequeueing any cells, call this method or the
register(_:forCellReuseIdentifier:) method to tell the table view how
to create new cells. If a cell of the specified type is not currently
in a reuse queue, the table view uses the provided information to
create a new cell object automatically.
This is the standard procedure I apply while working with Custom Cells (if you are using xib) :
Set cell's identifier in Xib's attribute inspector :
Register Xib :
self.tableTasks.register(UINib(nibName: "TaskCell", bundle: nil), forCellReuseIdentifier: "taskCell")
However, if you are not using Xib and creating custom cell using code only, then use registeCell :
self.tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")
Are you using a xib for this cell? If so, none of the outlets will be connected if you just register the class of the cell. You need to register the actual xib file, so that everything can be connected correctly when the cell is created. Have a look at
-(void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier
https://developer.apple.com/documentation/uikit/uitableview/1614937-registernib
My method for register cell.
Syntax sugar
protocol BSCellProtocol {
// For `registerCell`
static var NibName: String! { get }
// For `registerCell`, `dequeueCellWithType`, and `dequeueHeaderFooterWithType`
static var Identifier: String! { get }
}
extension UITableView {
func registerCell(_ type: BSCellProtocol.Type) {
let nib = UINib(nibName: type.NibName, bundle: nil)
let identifier = type.Identifier!
self.register(nib, forCellReuseIdentifier: identifier)
}
func dequeueCellWithType<T: BSCellProtocol>(_ type: T.Type) -> T {
let cell = self.dequeueReusableCell(withIdentifier: type.Identifier) as! T
return cell
}
func dequeueCellWithType<T: BSCellProtocol>(_ type: T.Type, index: IndexPath) -> T {
let cell = self.dequeueReusableCell(withIdentifier: type.Identifier, for: index) as! T
return cell
}
}
Usage
class MyCustomCell: UITableViewCell, BSCellProtocol {
static var NibName: String! = "MyCustomCell"
static var Identifier: String! = "cellIdentifier_at_Xib"
#IBOutlet weak var lblTitle: UILabel!
// other IBOutlet components
}
// In ViewController, register cell
tableView.registerCell(MyCustomCell.self)
// dequeue cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// cell is `MyCustomCell` instance
let cell = tableView.dequeueCellWithType(MyCustomCell.self)
// configure cell ...
// ....
return cell
}
I had the same problem. I also was not using XIB for cell. My view was not connected to View in File's Owner Outlets. Maybe this info will help someone.
In my app I am using a custom tableViewCell using a xib file. I create the .xib file outlet the labels etc to my TableViewCell class
In my ViewController the code I used to populate and show the cell on the table view is as follows:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let transaction = statementArray[indexPath.row]
let cell = Bundle.main.loadNibNamed("StatementCell", owner: self, options: nil)?.first as! StatementCell
cell.transAmount.text = String(transaction.transAmount)
cell.transDesc.text = transaction.transDesc
cell.transFees.text = String(transaction.transFees)
return cell
}
I am aware that the way tableViews work is that they reuse the cell that goes off the screen. Is the way i am loading the .xib and populating the cell correct? Or do I have to add something to my code?
First you need to register your custom cell with UITableView
yourTableView.register(UINib(nibName: "StatementCell", bundle: nil), forCellReuseIdentifier: "cellIdentifier")
then in UITableView Delegate method cellForRowAt you need to write
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath) as! StatementCell
cell.textLabel?.text = "Sample Project"
return cell
now you can access your UITableViewCell properties with cell.propertyName
and you must take care that "cellIdentifier" and "forCellReuseIdentifier" both value must be same.
One more thing is you need to register your class for reuse identifier in viewDidLoad method.
YourTable.registerclass(tablecell, forCellReuseIdentifier: "identifier"
And make sure you have connect all the required outlets.
FIrst Register Custom cell nibCalss in tableview
let str1 : NSString = "StatementCell"
tableView.register(UINib(nibName: "StatementCell", bundle: nil), forCellReuseIdentifier: str1 as String)
Now initialise tableviewcell
let cell1:StatementCell = tableView.dequeueReusableCell(withIdentifier: str1 as String) as! StatementCell!
Now access tableviewcell outlet collection.
I have made a ViewController, in that ViewController, I have made a TableView , in the TableView I have added a TableViewCell.
In the TableViewCell, I have added a text label and an image.
Iv'e made a cocoa touch file named customCell and connected it with the TableView Cell.
In the ViewController file I wrote this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:customCell = tableView.dequeueReusableCellWithIdentifier("cell") as! customCell
cell.imageCountry.image = UIImage(named: "2xd.png")
cell.nameCountry.text = "hey"
return cell
This is what i wrote in the customCell file:
import UIKit
class customCell: UITableViewCell {
#IBOutlet var imageCountry: UIImageView!
#IBOutlet var nameCountry: UILabel!
}
Iv'e connected the TableView & the ViewController with the DataSource & Delegate.
When I run my code this is the error I get:
Could not cast value of type 'UITableViewCell' (0x10d1119f0) to 'refreshing.customCell' (0x10b2f6dd0).
*refreshing is the name of the project.
And the green line of the bugger is set to this line:
let cell:customCell = tableView.dequeueReusableCellWithIdentifier("cell") as! customCell
Any suggestions?
you are using the old decking method, that either rquires you to create the cell or use the new that takes the indexPath
let cell:customCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath:indexPath) as! customCell
if it is still failing, you need to register the cell, either by setting it up in the storyboard or by registering either a class or a nib file in code.
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerNib(UINib(nibName: "customCell", bundle: nil), forCellReuseIdentifier: "cell")
}
or
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(customCell.self, forCellReuseIdentifier: "cell")
}
You need to set your custom class as the cell's class here ^
And to subclass, ensure in your CustomClass.h file you have
#interface CustomClass : UITableViewCell
let cell = tableView!.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as MessageTableViewCell
let cell2 = tableView!.dequeueReusableCellWithIdentifier("Cell2", forIndexPath: indexPath) as MessageTableViewCell
The first cell is recognized fine. The second, is not. I have a storyboard with the proper identifiers set for each prototype cell. The (dynamic) tableView has both cells on it, which should be fine from what I understand. This is the exact error I receive:
* Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'unable to dequeue a cell
with identifier Cell2 - must register a nib or a class for the
identifier or connect a prototype cell in a storyboard
This would make perfect sense if the identifier for that second prototype cell wasn't "Cell2", however it is.
Here is the code in the entire function, notice how I am not even returning cell 2, simply dequeuing it:
override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
let cell = tableView!.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as MessageTableViewCell
let cell2 = tableView!.dequeueReusableCellWithIdentifier("Cell2", forIndexPath: indexPath) as MessageTableViewCell
if UIApplication.sharedApplication().statusBarOrientation.isLandscape == true {
cell.messageLabel.preferredMaxLayoutWidth = cell.frame.size.width - 80
} else {
cell.messageLabel.preferredMaxLayoutWidth = cell.frame.size.width - 35
}
preferredWidth = cell.messageLabel.preferredMaxLayoutWidth
cell.messageLabel.text = friends[indexPath!.row]
cell.messageLabel.sizeToFit()
cell.messageLabel.setNeedsDisplay()
return cell
}
It crashes on that second line (inside the function).
Note: I am now using XCode 6 Beta 4.
I experienced this as well. Try this:
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
I created a new nib, recreated the cell in there, and inserted this code, which all in combination solved the problem.
var nibName = UINib(nibName: "MainTableViewCell", bundle:nil)
self.tableView.registerNib(nibName, forCellReuseIdentifier: "SecondCell")