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.
Related
I have used a tableView (myTableView) on a usual UIViewController class. I wish to use reusable cells in this tableView to save memory. I did not create separate XIB and dragged and dropped a tableView component on to the viewController.
The cells have been created with a new class HistoryTableViewCell of type UITableViewCell and this class also has an XIB.
I have also created a tableViewCell and its XIB and used the following code in the tableView(_,cellForRowAt:) method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "historyReuseIdentifier", for: indexPath) as! HistoryTableViewCell
cell.meetingDateLabel.text = historyArray![indexPath.section]
return cell
}
This line of code works fine with a tableViewController when I add the following line in the viewDidLoad() method:
tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "reuseIdentifier")
But the tableView.register property cannot be used with a tableView. How do I make use of the reusable cells here?
Lets say your xib is ok, everything works fine and the only thing left is to register the nib.
First declare your table view:
#IBOutlet weak var tableView: UITableView!
In the viewDidLoad() :
tableView.register(UINib(nibName: "HistoryTableViewCell", bundle: nil) , forCellReuseIdentifier: "historyReuseIdentifier")
Also check your tableView's dataSource and delegate.
The answer was actually quite simple. I figured it out after reading a few of the other answers.
All I needed was to replace this line:
tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "reuseIdentifier")
with this one:
UITableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "reuseIdentifier")
Since there is no table view by the name tableView, you need to access the UITableView class.
Do you want to reuse the cells thats ok, to use them you need to register it first..suppose you have multiple tableView in a single ViewController, then you have to register each cell with respective tableView.
just register the tableViewCell with respective tableView and use its reusableIdentifier which you have used while registering the tabelViewcell.
Try to create it directly in cellForRowAt indexPath: like this. Here no need of tableView.register(UINib(nibName: "TableViewCell", ... line.
//And replace names with your names
var cell = tableView.dequeueReusableCell(withIdentifier:"cell") as? TableViewCell
if cell == nil {
cell = Bundle.main.loadNibNamed("TableViewCell",owner: self, options: nil)?.first as? TableViewCell
}
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?
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.
I got stuck with simple issue and can't find any solution.
MyCell.xib has fileowner MyCell : UITableViewCell class.
I use it like that:
viewDidLoad method:
let nib = UINib(nibName: "MyCell", bundle: nil)
self.tableView.register(nib, forCellReuseIdentifier: "myIdentifier")
tableView cellForRowAt method:
let cell = tableView.dequeueReusableCell(withIdentifier: "myIdentifier", for: indexPath) as? MyCell
It works good.
I subclass my class to add some new methods:
class SuperCell : MyCell {
func coolMethod {
print("cool")
}
}
And try to use it like that:
let cell = tableView.dequeueReusableCell(withIdentifier: "myIdentifier", for: indexPath) as? SuperCell
it returns nil
How can I make it work?
I tried to create prototype cell in InterfaceBuilder with identifier myIdentifier and with class SuperCell, but it didn't help.
Why do I need it
I just want to use the same view (xib) for different cell classes.
In my case I have common cell (MyCell) with view (xib). MyCell completely describes fields (IBOutlets). Also I want to create some another cell classes that subclasses MyCell, but they will provide some behaviour of these IBOutlets. For example FirstMyCell : MyCell will have method setFieldsFrom(objectOne: ObjectOne) and SecondMyCell : MyCell will have another method setFieldsFrom(anotherObject: ObjectAnother).
Of course, I can just add this two methods into my MyCell class, but it will be unclean.
Do not set the files owner (remove it)
Make sure your your XIBs Custom Class is set to SuperCell: