In my iOS app I have a table with 4 sections. I created a subtitle cell for each section and each cell has got its own identifier as you can see from the screenshot:
The problem is that when I need to insert a cell in that section by creating it with its identifier, I get am exception saying 'unable to dequeue a cell with identifier ... '
Here's my method:
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell?
var selectedStatus:String
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier("OpenTasks",
forIndexPath: indexPath) as! UITableViewCell
selectedStatus = "Aperti"
break
case 1:
let cell = tableView.dequeueReusableCellWithIdentifier("ClosedTasks",
forIndexPath: indexPath) as! UITableViewCell
selectedStatus = "Chiusi"
break
case 2:
let cell = tableView.dequeueReusableCellWithIdentifier("ExpiredTasks",
forIndexPath: indexPath) as! UITableViewCell
selectedStatus = "Scaduti"
break
case 3:
let cell = tableView.dequeueReusableCellWithIdentifier("SuspendedTasks",
forIndexPath: indexPath) as! UITableViewCell
selectedStatus = "Sospesi"
break
default:
let cell = tableView.dequeueReusableCellWithIdentifier("",
forIndexPath: indexPath) as! UITableViewCell
selectedStatus = ""
break
}
let task = self.organizedTasks.items[selectedStatus]![indexPath.row]
cell?.textLabel?.text = task.titolo
cell?.detailTextLabel?.text = task.priorita
return cell!
}
I don't know what I am missing...
Can you help?
You are making mistake in you code by using let to every cell variable.
This is right way to do it:
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell?
var selectedStatus:String
switch indexPath.section {
case 0:
cell = tableView.dequeueReusableCellWithIdentifier("OpenTasks",
forIndexPath: indexPath) as! UITableViewCell
selectedStatus = "Aperti"
break
case 1:
cell = tableView.dequeueReusableCellWithIdentifier("ClosedTasks",
forIndexPath: indexPath) as! UITableViewCell
selectedStatus = "Chiusi"
break
case 2:
cell = tableView.dequeueReusableCellWithIdentifier("ExpiredTasks",
forIndexPath: indexPath) as! UITableViewCell
selectedStatus = "Scaduti"
break
case 3:
cell = tableView.dequeueReusableCellWithIdentifier("SuspendedTasks",
forIndexPath: indexPath) as! UITableViewCell
selectedStatus = "Sospesi"
break
default:
cell = tableView.dequeueReusableCellWithIdentifier("",
forIndexPath: indexPath) as! UITableViewCell
selectedStatus = ""
break
}
let task = self.organizedTasks.items[selectedStatus]![indexPath.row]
cell?.textLabel?.text = task.titolo
cell?.detailTextLabel?.text = task.priorita
return cell!
}
Well first of all, This looks like a disaster of an approach to using a tableview.
Secondly, your first identifier in the screenshot is OpenTask (singular), but your code is looking for OpenTasks (plural).
Hope this helps
Related
i have a problem with the following code that manage two uitableview in a viewcontroller. When insert the data in a modal controller in the 'directionTableView' give a follow error:
Thread 1: signal SIGABRT
'Could not cast value of type 'UITableViewCell' (0x1059e7560) to 'FoodTime.DirectionRecipeTableViewCell' (0x101388bf0). 2018-05-23 21:50:12.160281+0200 FoodTime[4577:360265] Could not cast value of type 'UITableViewCell' (0x1059e7560) to 'FoodTime.DirectionRecipeTableViewCell' (0x101388bf0).'
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var cell = UITableViewCell()
if (tableView == self.ingredientTableView)
{
let cell = tableView.dequeueReusableCell(withIdentifier: "newIngredientCell", for: indexPath) as! IngredientRecipeTableViewCell
let ingredientCell = ingredients[indexPath.row]
cell.textLabel?.text = ingredientCell.titleIngredientRecipe
cell.detailTextLabel?.text = ingredientCell.subtitleIngredientRecipe
}
else if (tableView == self.directionTableView)
{
//Thread 1: signal SIGABRT on next line
let cell = tableView.dequeueReusableCell(withIdentifier: "newDirectionCell", for: indexPath) as! DirectionRecipeTableViewCell
let directionCell = directions[indexPath.row]
cell.textLabel?.text = directionCell.directionSection
cell.detailTextLabel?.text = directionCell.directionText
}
return cell
}
Away from the problem the first line
var cell = UITableViewCell()
is actually what is being returned cells inside the if statements are local variables
So try this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
if (tableView == self.ingredientTableView)
{
let cell = tableView.dequeueReusableCell(withIdentifier: "newIngredientCell", for: indexPath) as! IngredientRecipeTableViewCell
let ingredientCell = ingredients[indexPath.row]
cell.textLabel?.text = ingredientCell.titleIngredientRecipe
cell.detailTextLabel?.text = ingredientCell.subtitleIngredientRecipe
return cell
}
else
{
let cell = tableView.dequeueReusableCell(withIdentifier: "newDirectionCell", for: indexPath) as! DirectionRecipeTableViewCell //Thread 1: signal SIGABRT
let directionCell = directions[indexPath.row]
cell.textLabel?.text = directionCell.directionSection
cell.detailTextLabel?.text = directionCell.directionText
return cell
}
}
Also make sure that you register every tableview with the corresponding cell
error i so easy
you declare this
var cell = UITableViewCell()
then you create new one
let cell = tableView.dequeueReusableCell(withIdentifier: "newIngredientCell", for: indexPath) as! IngredientRecipeTableViewCell
just remove let
Also
In interface builder make sure that cell with newDirectionCell is DirectionRecipeTableViewCell and same for another cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var cell = UITableViewCell()
if (tableView == self.ingredientTableView)
{
cell = tableView.dequeueReusableCell(withIdentifier: "newIngredientCell", for: indexPath) as! IngredientRecipeTableViewCell
let ingredientCell = ingredients[indexPath.row]
cell.textLabel?.text = ingredientCell.titleIngredientRecipe
cell.detailTextLabel?.text = ingredientCell.subtitleIngredientRecipe
}
else if (tableView == self.directionTableView)
{
//Thread 1: signal SIGABRT on next line
cell = tableView.dequeueReusableCell(withIdentifier: "newDirectionCell", for: indexPath) as! DirectionRecipeTableViewCell
let directionCell = directions[indexPath.row]
cell.textLabel?.text = directionCell.directionSection
cell.detailTextLabel?.text = directionCell.directionText
}
return cell
}
In my UITableView I have Four cell. Each cell has its own class. But I can only return one of the cells. Here is my code
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let firstCell = tableView.dequeueReusableCellWithIdentifier("FirstCell", forIndexPath: indexPath) as! FirstTableViewCell
let secondCell = tableView.dequeueReusableCellWithIdentifier("SecondCell", forIndexPath: indexPath) as! SecondTableViewCell
let thirdCelll = tableView.dequeueReusableCellWithIdentifier("ThirdCell", forIndexPath: indexPath) as! ThirdTableViewCell
let fourthCell = tableView.dequeueReusableCellWithIdentifier("FourthCell", forIndexPath: indexPath) as! FourthTableViewCell
return firstCell
}
How do I Correctly sub class and return them
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 // or your custom condition
{ let firstCell = tableView.dequeueReusableCellWithIdentifier("FirstCell", forIndexPath: indexPath) as! FirstTableViewCell
return firstCell
}
else if indexPath.row == 1{
let secondCell = tableView.dequeueReusableCellWithIdentifier("SecondCell", forIndexPath: indexPath) as! SecondTableViewCell
return secondCell
}
indexPath.row == 2{
let thirdCelll = tableView.dequeueReusableCellWithIdentifier("ThirdCell", forIndexPath: indexPath) as! ThirdTableViewCell
return thirdCelll
}
else{
let fourthCell = tableView.dequeueReusableCellWithIdentifier("FourthCell", forIndexPath: indexPath) as! FourthTableViewCell
return fourthCell
}
}
This function is called multiple times. The indexPath.row would be used to determine which cell to return. You should check the value of this and only return the requested cell.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell
switch indexPath.row {
case 0:
cell = tableView.dequeueReusableCellWithIdentifier("FirstCell", forIndexPath: indexPath) as! FirstTableViewCell
case 1:
cell = tableView.dequeueReusableCellWithIdentifier("SecondCell", forIndexPath: indexPath) as! SecondTableViewCell
case 2:
cell = tableView.dequeueReusableCellWithIdentifier("ThirdCell", forIndexPath: indexPath) as! ThirdTableViewCell
case 3:
cell = tableView.dequeueReusableCellWithIdentifier("FourthCell", forIndexPath: indexPath) as! FourthTableViewCell
}
return cell;
}
I am sure this question have been asked before but I can't find an answer that solves my problem with nested if-else and switch-case logic.
I have a UITableView with two sections, each sections has two custom cells. That is it it. 4 cells. But no matter what I do I get "Missing return in a function expected to return UITableViewCell"
Question How can I change this setup so that I get an else statement at the bottom that will satisfy swift logic?
Any help would be very much appreciated
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.section == 0{
switch (indexPath.row) {
case 0:
let cell0: SettingsCell! = tableView.dequeueReusableCellWithIdentifier("cell0", forIndexPath: indexPath) as! SettingsCell
cell0.backgroundColor = UIColor.redColor()
break
case 1:
let cell1: SettingsCell! = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! SettingsCell
cell1.backgroundColor = UIColor.whiteColor()
break
default:
break
}
}
if indexPath.section == 1{
switch (indexPath.row) {
case 0:
let cell10: SettingsCell! = tableView.dequeueReusableCellWithIdentifier("cell10", forIndexPath: indexPath) as! SettingsCell
cell10.backgroundColor = UIColor.redColor()
break
case 1:
let cell11: SettingsCell! = tableView.dequeueReusableCellWithIdentifier("cell11", forIndexPath: indexPath) as! SettingsCell
cell11.backgroundColor = UIColor.whiteColor()
break
default:
break
}
}
}
Declare the cell at the start of the method,
assign a value to the cell depending on section and row number,
throw a fatalError() in all cases that "should not occur",
return the cell.
Also note that the break statements are not needed. The default
behavior in Swift is not to fall through to the next case.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: SettingsCell
switch(indexPath.section) {
case 0:
switch (indexPath.row) {
case 0:
cell = tableView.dequeueReusableCellWithIdentifier("cell0", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.redColor()
case 1:
cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.whiteColor()
default:
fatalError("Unexpected row \(indexPath.row) in section \(indexPath.section)")
}
case 1:
switch (indexPath.row) {
case 0:
cell = tableView.dequeueReusableCellWithIdentifier("cell10", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.redColor()
case 1:
cell = tableView.dequeueReusableCellWithIdentifier("cell11", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.whiteColor()
default:
fatalError("Unexpected row \(indexPath.row) in section \(indexPath.section)")
}
default:
fatalError("Unexpected section \(indexPath.section)")
}
return cell
}
The fatalError() error function is marked as #noreturn, so the
compiler knows that program execution will not continue from the
default cases. (This also helps to find logic errors in the program.)
The compiler verifies that a value is assigned to cell in all
other cases.
The possibility to initialize a constant (let cell ...) in this
way is new in Swift 1.2.
Alternatively, you can create a cell and return it "immediately"
in each case:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch(indexPath.section) {
case 0:
switch (indexPath.row) {
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier("cell0", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.redColor()
return cell
case 1:
let cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.whiteColor()
return cell
default:
fatalError("Unexpected row \(indexPath.row) in section \(indexPath.section)")
}
case 1:
switch (indexPath.row) {
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier("cell10", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.redColor()
return cell
case 1:
let cell = tableView.dequeueReusableCellWithIdentifier("cell11", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.whiteColor()
return cell
default:
fatalError("Unexpected row \(indexPath.row) in section \(indexPath.section)")
}
default:
fatalError("Unexpected section \(indexPath.section)")
}
}
Again, calling fatalError() solves the "missing return expected" compiler
error.
This pattern can be useful if there are different kinds of cells
(with different classes) created in each case.
You must return a cell, if the section is number 2 this methods won't be returning anything, well it's the case when u specify secitons more than two. Solution
Second "if" will be "else" part
Limit number of section
You're missing in you method the return statement.
Example with return statement.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.section == 0{
switch (indexPath.row) {
case 0:
let cell: SettingsCell! = tableView.dequeueReusableCellWithIdentifier("cell0", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.redColor()
break
case 1:
let cell: SettingsCell! = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.whiteColor()
break
default:
let cellId: NSString = "Cell"
var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellId) as UITableViewCell
break
}
}
if indexPath.section == 1{
switch (indexPath.row) {
case 0:
let cell: SettingsCell! = tableView.dequeueReusableCellWithIdentifier("cell10", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.redColor()
break
case 1:
let cell: SettingsCell! = tableView.dequeueReusableCellWithIdentifier("cell11", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.whiteColor()
break
default:
let cellId: NSString = "Cell"
var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellId) as UITableViewCell
break
}
}
return cell
}
you can use else if
like this :
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.section == 0{
switch (indexPath.row) {
case 0:
let cell: SettingsCell! = tableView.dequeueReusableCellWithIdentifier("cell0", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.redColor()
break
case 1:
let cell: SettingsCell! = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.whiteColor()
break
default:
break
}
else if indexPath.section == 1{
switch (indexPath.row) {
case 0:
let cell: SettingsCell! = tableView.dequeueReusableCellWithIdentifier("cell10", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.redColor()
break
case 1:
let cell: SettingsCell! = tableView.dequeueReusableCellWithIdentifier("cell11", forIndexPath: indexPath) as! SettingsCell
cell.backgroundColor = UIColor.whiteColor()
break
default:
break
}
}
return cell
}
}
it may help you try it
I'm trying to complete a UITableView and i'm receiving an error on the final part of the code for one line.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
//ERROR IS IN THE LINE ABOVE ("anyobject" is not convertible to "UItableViewCell"
if (indexPath.section == 1) {
let (unit, availability) = myUnits[indexPath.row]
cell.textLabel?.text = unit
cell.detailTextLabel?.text = availability
} else {
let (assessment, mark) = myAssessments[indexPath.row]
cell.textLabel?.text = assessment
cell.detailTextLabel?.text = mark
}
return cell
}
You have to tell the compiler that your cell is of the UITableViewCell class, which means downcasting using the ! mark:
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
i've created a UITableView and used the standard UITableViewCell and added a accessoryType, but whatever i do it does not seem to appear. How come is that? here is my code:
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
switch indexPath.row
{
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = "Kontakt os"
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cell
case 1:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = "Privatpolitik"
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cell
case 2:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = "Vilkår"
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cell
default:
println()
}
return nil
}