Using a variable for dequeueReusableCellWithIdentifier - ios

I'm building a table that has two cells of the same class but of different identifiers.
I am using a segmented control to display either or.
I believe everything is hooked up properly on Storyboard, however,
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let friendRequest = self.friendRequestsToDisplay[indexPath.row]
requestDirection = isAnIncomingRequest ? "IncomingRequestCell" : "OutgoingRequestCell"
if let cell = tableView.dequeueReusableCellWithIdentifier(requestDirection) as? RequestCell {
cell.configureCell(friendRequest, isAnIncomingRequest: isAnIncomingRequest)
return cell
} else {
return UITableViewCell()
}
}
FAILS AT dequeueReusableCellWithIdentifier, according to breakpoints, with:
fatal error: unexpectedly found nil while unwrapping an Optional value
After hard coding the Identifiers ("IncomingRequestCell" and "OutgoingRequestCell" in the dequeueReusable... method as suggested in the comments, it appears that these values are the source of the problem. However, they properly identify their respective UITableViewCells in IB.
Any ideas?

Why you use global variable for reuseIdentifier and update it every time? You can use local var for it.
Also avoid using dequeueReusableCellWithIdentifier, please use dequeueReusableCellWithIdentifier:forIndexPath: instead. I had some strange issues in one of my previous project because of it.
Here is quick example, which works like a charm:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let identifier = (indexPath.row == 0) ? "Cell1" : "Cell2"
let cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath)
self.configureCell(cell, atIndexPath: indexPath)
return cell
}
UPDATE: After investigation, we figured, that problem was in custom cell class initialization code.

If everything is hooked up properly - which means that you correctly set your reuseIdentifiersin IB and the UITableViewCells are prototyp cells within your UITableView (and not loaded from a nib - which requires manually registering the UITableViewCells), than just use
dequeueReusableCellWithIdentifier:forIndexPath:

Related

Swift: Searching the object from the memory address [duplicate]

I usually never have a problem with this step, but for some reason when I re set up my storyboard now I have an issue with this part of my code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell
(cell as! TableViewCell).usernameLabel.text = friendsArray[indexPath.row] as String
return cell
}
I have done all of the obvious stuff like making sure the cell identifier is "Cell".
My error is this:
Could not cast value of type 'UITableViewCell' (0x1094ada18) to 'YOpub.TableViewCell' (0x106620410).
EDIT: Problem was I had self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell") in my didLoad function. After removing this line my code worked again.
You may have forgotten to tell the storyboard that this cell is a TableViewCell. Select the prototype cell and set the Custom Class in the Identity inspector.
You may have called registerClass:forCellReuseIdentifier:. If so, delete that call; it actually prevents us from getting the cell from the storyboard.
You are calling tableView.dequeueReusableCellWithIdentifier. That is a big mistake. You should call tableView.dequeueReusableCellWithIdentifier:forIndexPath:.
One of the reason,May be in Identity inspector module is different then your project name .

dequeueReusableCellWithIdentifier returning the same cells for different indexPath

using dequeueReusableCellWithIdentifier works for the first 7 cells and then it randomly starts to reuse the cells from 1-7 for 8-14 and so on... However it should be creating new cells as they dont exist yet.
This is my code-
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
NSLog(indexPath.description)
var cell = (tableView.dequeueReusableCellWithIdentifier("matchCell", forIndexPath: indexPath)) as! MatchCell
if (cell.created == nil) {
cell = configureCell(cell, withIndex: indexPath.section)
}
return cell
}
No Idea why this is happening. It works fine for the first 7 cells...
Cells are reusable so once they go off-screen they will be returned to you from dequeueReusableCellWithIdentifier so your if (cell.created == nil) will not be true for reused cells.
There are two ways to solve this:
Don't check for cell.created == nil
Override prepareForReuse in your MatchCell and do any cleanup for reuse (and set created to be nil)
I personally like the second option.
Apple Docs has more info on prepareForReuse.

Calling super.tableView(tableView: UITableView, cellForRowAtIndexPath... with reuseIdentifier

First, I wanted to point out the reason I want to make a common call, when a reusable cell is dequeued in a base class, it's because of this line of code you will see again soon further in my question:
cell.backgroundColor = cell.contentView.backgroundColor;
This is a bug fix for iPad not respecting the UITableView.backgroundColor = myCustomColor and UITableViewCell.backgroundColor = clearColor I have set. iPad displays white instead, everything is fine in iPhone versions, you can see this bug here, I have to set the background color again each time the cell is dequeued that is the only solution that works for me. I am trying to do this once in my base class, and come up with a solution where I do not have to remember to call a func for every child class (might not be possible).
I have a couple custom UITableViewControllers classes, let's call them ATableViewController and BTableViewController they inherit from a base class called UIBaseDashboardTableViewController which inherits from UITableViewController.
I am generating dynamic Prototype Table cells and making use of the function below in ATableViewController and BTableViewController:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("ATableViewCellId", forIndexPath: indexPath)
//common setting to fix always white background in iPad bug
cell.backgroundColor = cell.contentView.backgroundColor;
return cell
}
The TableViewCell Id ACustomTableCellId is unique or different for ATableViewController and BTableViewController. I have a common setting for all my UITableViewControllers that inherit from my base class, UIBaseDashboardTableViewController. You can see the backgroundColor line of code above is my common setting that will be the same in all child classes of UIBaseDashboardTableViewController. In each child class I first tried to do the following:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
super.tableView(tableView: tableView, cellForRowAtIndexPath: indexPath)
...
}
But that is not going to work, I need the ReusableCellIndentifer.
My current solution, which really is just fine probably, is the following, in my child classes I have the following:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let data = dataArray[indexPath.row]
let dequeuedCell = tableView.dequeueReusableCellWithIdentifier("BTableViewCellID", forIndexPath: indexPath)
let cell = dequeuedCell as! MyCustomTableViewCell
// Configure the cell...
cell.model = data
//call common settings for cells function in base class
super.setDequeueReusableCellCommon(cell)
return cell
}
And then in my base class UIBaseDashboardTableViewController I implemented:
func setDequeueReusableCellCommon(cell: UITableViewCell) {
cell.backgroundColor = cell.contentView.backgroundColor
}
The only downside to this is that I have to remember to call super.v setDequeueReusableCellCommon in all my child classes.
Any better suggestions on how solve this?
You are changing background color for cell, but made inheritance for tableViews. Use inheritance for tableViewCell, not the whole tableView. And in root class for tableViewCell setup self.backgroundColor = self.contentView.backgroundColor in awakeFromNib method.

Modify custom made cells from storyboard

I have an iOS app with a lot of static cells (for a preferences view), so it makes sense to put all of that in storyboard, but I would like to be able to add a checkmark to them based on if the preference is set or not.
I have my delegate method setup
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
}
I just can't figure out how to "grab" the cell from the interface builder using the indexpath so that I can decide programmatically whether or not I should add a checkmark. I have a feeling there is some sort of superclass/delegate method I can call, but I'm not sure what it is. Thanks.
When you use static cells, you need to put them in a UITableViewController because there's magic going in there. Under the hood, it implements those data source methods for you. But you can override them. The important thing is that you need to call the super version to let it do it's job. If the method returns a value you need to return that too.
So in your case:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)
let isChecked = true // put your logic to determine whether the cell should be checked here
cell.accessoryType = isChecked ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone
// ...
return cell
}

Swift TableViewController reuseIdentifier never works

I'm working in Swift with one TableViewController with one prototype cell. The cell has a reuse identifier specified in the storyboard, but it never dequeues properly. I always get the "unexpectedly found nil while unwrapping an Optional value" error.
I've properly registered the class as follows:
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "myNewCell")
The offending code is:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("myNewCell") as UITableViewCell
let textField = cell.viewWithTag(123) as UITextField
textField.text = "test"
return cell
}
I feel like I've tried everything here but it never properly gives a cell with that identifier. Even using the fallback (if nil, create a cell with that identifier) still gives the error. It's definitely having trouble getting a cell with that identifier, but it's registered and specified in the storyboard... Any assistance is greatly appreciated!
When using cell prototypes, you do not call registerClass. The storyboard does that for you. If the cell prototype has its identifier specified, then just all dequeueReusableCellWithIdentifier and it should find your cell prototype without incident.
I'd suggest checking the spelling/capitalization of the identifier in storyboard and make sure it is identical to what is used in cellForRowAtIndexPath code.
I notice that you are trying to access a cell's label using a tag number. Nowadays, when dealing with custom cell layouts, we'd generally create our own table view subclass, e.g.:
// CustomTableViewCell.swift
import UIKit
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var customTextField: UITextField! // note, I would use something other than textLabel to avoid confusion with base class
}
We'd then go to our cell prototype and specify its base class:
We'd also set the cell prototype's identifier:
We'd then hook up the outlet between the cell prototype and our custom class #IBOutlet.
Having done all of that, the cellForRowAtIndexPath would be:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myNewCell", forIndexPath: indexPath) as CustomTableViewCell
cell.customTextField.text = "Row \(indexPath.row)"
return cell
}
If dequeueReusableCellWithIdentifier is giving you problems then just don't use it.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = UITableViewCell()
let textField = cell.viewWithTag(123) as UITextField
textField.text = "test"
return cell
}

Resources