How do I change the following closure so that cell is 'weak'? :
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath as IndexPath) as? PlayerTableViewCell else {
fatalError("The dequeued cell is not an instance of PlayerTableViewCell")
}
I am sure there is a simple way to achieve this but I have been unable to determine the correct way to handle this.
Thanks
A duplicate call to dequeueReusableCell was causing a memory consumption problem, which led me to think I had a strong reference that needed to be weakened.
Removing this erroneous extra call solved the underlying issue I thought needed a fix.
Related
When I was learning about tableviews the tutorials I followed used the following code-
guard let cell = tableView.dequeueReusableCell(withIdentifier: Self.reminderListCellIdentifier, for: indexPath) as? ReminderListCell else {
return UITableViewCell()
}
I just came across example code from Apple which is;
guard let cell = tableView.dequeueReusableCell(withIdentifier: Self.reminderListCellIdentifier, for: indexPath) as? ReminderListCell else {
fatalError("Unable to dequeue ReminderCell")
}
What should I implement? fatalError causes a crash I believe. Is the the desired behaviour?
None of the suggestions. Force unwrap the cell
let cell = tableView.dequeueReusableCell(withIdentifier: Self.reminderListCellIdentifier, for: indexPath) as! ReminderListCell
In practice it causes the same behavior as the fatalError.
The code must not crash if everything is hooked up correctly. The potential mistake is a design mistake.
The first snippet is pretty silly because in case of the mentioned design mistake nothing will be displayed and you have no idea why.
Force unwrapping is not evil per se.
I am new to the iOS programming scene and I recently came across some code examples online of implementations like:
functableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: customCellIdentifier, for: indexPath) as? CustomCell
if (cell == nil) {
cell = CustomCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: customCellIdentifier) asCustomCell
}
...
}
Where the author tried to handle the event where dequeueReusableCell return nil.
But from my limited personal experience with UITableView and custom cells, I have yet to encounter a time when dequeueReusableCell returned me nil.
From researching, I found the reason could be
"The dequeue… methods try to find a cell with the given reuse
identifier that is currently offscreen. If they find one, they return
that cell, otherwise they return nil."
from MrTJ's answer here
But that has never happened once to me. When I purposely give it a wrong identifier, a runtime error would occur but not once was nil returned. I wonder when exactly that would happen and if handling it is really necessary.
That code isn't correct. The older form of dequeueReusableCell without the indexPath parameter returns nil when there isn't an available cell in the reuse pool (i.e. when the table view first appears). In that case it is your responsibility to allocate a cell.
The newer form of dequeueResuableCell, shown in your question, will always return a cell as it allocates a cell if required.
The expression in your question can return nil if the conditional downcast fails (that is, the cell that was returned wasn't an instance of CustomCell).
I would argue that this represents a serious misconfiguration somewhere and should be found during development. For this reason a forced downcast is normally used; during development you get a crash, fix the problem and move on.
let cell = tableView.dequeueReusableCell(withIdentifier: customCellIdentifier, for: indexPath) as! CustomCell
The code in your question is some sort of Frankenstein mixture of the old and the new.
The program is building successfully, but when it goes into the simulation, it crashes, and the fatal error message is logged to console.
The line that triggers the error is:
let cell = self.tableview?.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCell
Is cell returning nil? You need to make sure that you're passing the correct identifier of the UITableViewCell in your storyboard to the withIdentifier: "cell" parameter. Also, what is being logged to the console when you get this error? Many times it will point to the solution.
Give same identifier "cell" in storyboard.
I am trying to add a custom cell to tableview in Swift3 but getting a strange error. Here is the screenshot of error.
Write indexPath in place of IndexPath like this:
let cell = tableview.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell
Also, make sure that CustomCell is subclass of UITableViewCell.
Replace the placeholder IndexPath with lowercase indexPath
Placeholders – with a light blue background – are tokens which indicate the expected types of the parameters.
But you got more serious issues than that error.
Your CustomCell class does not inherit from UITableViewCell. Change it to:
class CustomCell:UITableViewCell {
// your custom cell implementation
}
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomTableViewCell
It's standard sentence that implements the table view's cell's properties. But Tailor (it's a Swift analyzer/linter) warns about you shouldn't forced the CustomTableViewCell as as! If I used to as as?, I have to implement cell's properties as cell!. But Tailor don't warn about [forced-type-cast] Force casts should be avoided. What's the reason of this? How can I implement cell's without unwrap of cell as cell! What's the correct programming paradigms for forced casts operations in Swift?
I am not familiar with "Tailor" but most likely the reason it is giving you this warning is because if a force cast fails then obviously your program will crash and thats never good.
The as! operator does have its place if you are 100% sure that what you are casting is of that type. But, even then its better to be safe than sorry and you should use a guard or if let statement instead in order to handle a failed cast.
if let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as? CustomTableViewCell {
//do what you like with cell
}
or
guard let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as? CustomTableViewCell else {
//abort current scope, return, break, etc. from scope.
}
//do what you like with cast cell