Connect custom table view cell to separate view controller - ios

So I'm trying to connect my custom table view cell into a table view in my main VC. The cell has its own xib file and its own swift file. I originally had the cell set up as a custom prototype cell in the table.
So the problem I have is in connecting my new custom cell to the viewcontroller. The code I have now is:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->
UITableViewCell {
let cell = table.dequeueReusableCell(withIdentifier: "cell")! as! CustomTableViewCell
return cell
}
Of course this set up is not working. The error I get during runtime is: "Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value" which I assume is referring to "cell" identifier. So my question is, can I connect my cell to this function, or do I need a new one to initiate and return "cell" to this table view?

You need to register the cell with the UITableView before you can use it. In your viewDidLoad method you need something like the following.
let nib = UINib(nibName: "CustomTableViewCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "cell")

Related

How do I reuse xib files across the app? Or does the IBOutlets get inherited?

I have created xib file which is sort of a template to the different table view cells I will be having. The xib has a left label and a button on the right. The actions will be different when button is clicked, so I created a .swift file for the xib which has outlets connected to it and then I created 2 sub-classes out of the .swift file which will basically set the target on button and perform different actions. However this doesn't work and the controls are not showing up on the app.
Custom xib file and base swift class for the xib:
Sub-class from LeftLabelRightButton swift class:
Registering xib in view controller and cell for row at index path:
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "LeftLabelRightButton", bundle: nil), forCellReuseIdentifier: "myCell")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "myCell") as? SampleSubClass {
cell.selectionStyle = UITableViewCell.SelectionStyle.none
cell.leftLabel.text = "Hello World"
cell.leftLabel.textAlignment = .left
}
}
I am not getting any errors with this, but I don't see the label or the button if I dequeue the cell as SampleSubClass.
If I do this then I see the label and button on the app:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "myCell") as? LeftLabelRightButton {
cell.selectionStyle = UITableViewCell.SelectionStyle.none
cell.leftLabel.text = "Hello World"
cell.leftLabel.textAlignment = .left
}
}
Can I dequeue the cell as sub-class? Does the outlet get inherited? My guess is with sub-class the outlets are not getting inherited.
First question : Yes. You can reuse xib across the app. Just register it to your UITableView or UICollectionView.
Second one : Yes also, but you can't use dequeueReusableCell. So i think it's useless.

Is it ok to register uitableviewcell in cellForRowAt.

Is it ok to register uitableviewcell in cellForRowAt. Before register i will check weather that cell is register or not by dequeue and nil check. Beacuse the tableview I m using its for genreic use across app and will not be sure about kind of cell will be needed.
var cell = tableView.dequeueReusableCell(withIdentifier: textFieldCellIdentifier) as! TextFieldCell!
if cell == nil {
tableView.register(UINib(nibName: "TextFieldCell", bundle: nil), forCellReuseIdentifier: textFieldCellIdentifier);
cell = tableView.dequeueReusableCell(withIdentifier: textFieldCellIdentifier) as! TextFieldCell!;
}
return cell!;
No it's bad.It will register multiple times because cellForRow atIndex will call several times based on your row counts & will call if you scrolled your tableView.
So i think better to register UITableViewCell in viewDidLoad method once.
tableView.register(UINib(nibName: "TextFieldCell", bundle: nil), forCellReuseIdentifier: textFieldCellIdentifier);
No, It is not OK!
Registration of cell into table is one time process.
If you will add register(_, forCellReuseIdentifier: _) to tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) then this registration will be done multiple times causing very small but unwanted performance issue so no need to do it.
Try putting it into viewDidLoad() or similar methods.

What's wrong with register(_:forCellWithReuseIdentifier:) on UICollectionView?

I'm working with an UICollectionView. As dequeueReusableCell(withReuseIdentifier:for:) expects You must register a class or nib file using the register(_:forCellWithReuseIdentifier:) method before calling this method, I added a line in my viewDidLoad func as
self.collectionView!.register(PhotoCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
Now when I'm using the cell for dequeuing and configuring, I'm getting error and app crashes.
fatal error: unexpectedly found nil while unwrapping an Optional value
This is my DataSource method:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier,
for: indexPath) as! PhotoCollectionViewCell
let aPhoto = photoForIndexPath(indexPath: indexPath)
cell.backgroundColor = UIColor.white
cell.imageView.image = aPhoto.thumbnail //this is the line causing error
return cell
}
And this is my PhotoCollectionViewCell class
class PhotoCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView! //I double checked this IBOutlet whether it connects with Storyboard or not
}
Original question
Now comes the interesting part.
I'm using a prototype cell in the UICollectionView and I set a reusable identifier from attributes inspector. Also I changed the custom class from identity inspector to my PhotoCollectionViewCell.
I searched for the same issue and found out that when using prototype cell, deleting
self.collectionView!.register(PhotoCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
from code will work. I gave it a try and it works.
But I'm curious to know the reason behind this issue. I couldn't reproduce the same issue with UITableView but with UICollectionView.
Not a possible duplicate:
This UICollectionView's cell registerClass in Swift is about how to register class in UICollectionView. But my question doesn't expect how to register. My question is about an issue that isn't true with UITableView class but with UICollectionView only. I'm expecting the actual difference between this conflicting issue.
There are 3 ways to register a cell (either for UITableView or UICollectionView).
You can register a class. That means the cell has no nib or storyboard. No UI will be loaded and no outlets connected, only the class initializer is called automatically.
You can register a UINib (that is, a xib file). In that case the cell UI is loaded from the xib and outlets are connected.
You can create a prototype cell in the storyboard. In that case the cell is registered automatically for that specific UITableViewController or UICollectionViewController. The cell is not accessible in any other controller.
The options cannot be combined. If you have a cell prototype in the storyboard, you don't have to register again and if you do, you will break the storyboard connection.
You can assign Nib to Collection view cell with an identifier as follows :
self.collectionView.register(UINib(nibName: "nibName", bundle: nil), forCellWithReuseIdentifier: "cell")
Hope it helps.

Swift custom table cell

I've been trying to use Custom Table cell in my swift app, and faced a problem: My application crashes when I run my app.
My custom table cell class is SimpleTableCell (Objective-C class)
and my cellForRowAtIndexPath method (swift) is:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("SimpleTableItem", forIndexPath: indexPath)
let data = TableData[indexPath.row]
cell.textLabel?.text = data.description
if (data.image == nil)
{
cell.imageView?.image = UIImage(named:"image.jpg")
load_image(image_base_url + data.imageurl!, imageview: cell.imageView!, index: indexPath.row)
}
else
{
cell.imageView?.image = TableData[indexPath.row].image
}
return cell
}
My app crashes with the error:
unable to dequeue a cell with identifier SimpleTableItem - must register a nib or a class for the identifier or connect a prototype cell in a storyboard
What does it mean?
In the storyboard, select your tableView cell and in the attributes inspector, set the identifier to "SimpleTableItem". Hope this helps
dequeueReusableCellWithIdentifier is trying to find a cell with the identifier "SimpleTableItem", but it seems that you haven't given a cell that identifier anywhere. One way to do this is to choose a cell in the Table View in Storyboard, go to the Attributes Inspector and set its identifier to SimpleTableItem.

swift custom UITableViewCell with TextView inside disappears

I am trying to get a custom tableView cell with a textView inside working in my tableView. I have made a custom UITableViewCell with a textView inside it.
I can get the custom made UITableViewCell with the textView inside to appear in the UITableView.
I can click inside the textView to type something, but when I finish typing and click on another tableViewCell, the first tableViewCell with the textView inside disappears. After disappearing, it becomes an empty tableViewCell. XCode gives this message:
"no index path for table cell being reused"
However, when I scroll away in the tableView and scroll back to the empty tableViewCell, it reappears.
I don't know how to keep the tableViewCell from disappearing. It seems like the answer has something to do with using the restorationIdentifier inside of UITableView, but I'm not sure how to use it. In the docs, it says to use restorationIdentifier for state preservation.
Here is the relevant code I have:
inside ViewDidLoad():
tableView.registerClass(PhotoAndRateTableViewCell.classForCoder(), forCellReuseIdentifier: ReuseIds.reviewCell)
tableView.registerNib(UINib(nibName: "PhotoAndRateTableViewCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: ReuseIds.reviewCell)
inside cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var section = indexPath.section
let cell = UITableViewCell()
var cell = tableView.dequeueReusableCellWithIdentifier(ReuseIds.reviewCell, forIndexPath: indexPath) as PhotoAndRateTableViewCell
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
You're misusing the dequeue procedure:
var cell = tableView.dequeueReusableCellWithIdentifier(ReuseIds.reviewCell, forIndexPath: indexPath) as? PhotoAndRateTableViewCell
if (cell == nil) {
cell = PhotoAndRateTableviewCell();
}
You want to reuse a cell if available, or create a new one if not. In your case, you're creating a cell every time (of the generic class) and then attempting to dequeue a cell from your custom class (which has never been created)
As far as preserving the data, you need to implement the prepareForReuse method in the table cell which should clear whatever index specific data was contained in the cell. Then in cellForRow you can re-set the data for the cell for re-appearance

Resources