i\'m trying to return different cells in a tableView. Normally in this case i would return different cells and then return nil at the bottom, but in this case it gives me an
As indicated in a previous answer for a similar question, -tableView:cellForRowAtIndexPath:
must return a UITableViewCell
. So you can't return nil
. However, I would also recommend to avoid returning the following codes at the end of -tableView:cellForRowAtIndexPath:
when you use if else or switch statements inside it:
//bad code design
var cell: UITableViewCell!
return cell
or:
//bad code design
var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
return cell
You can do better code than creating an UITableViewCell
instance that is never called just in order to silent Xcode warnings!
So what would be the solution?
The key thing is to be sure that your last possible value for an if else statement is set in else
(not in else if
). In the same way, the key thing is to be sure that your last possible value for a switch statement is set in default:
(not in case XXX:
).
Thus, your code should look like this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("CellZero", forIndexPath: indexPath) as UITableViewCell
/* ... */
return cell
} else if indexPath.row == 1 {
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("CellOne", forIndexPath: indexPath) as CellOne
/* ... */
return cell
} else { //set your last indexPath.row case in "else", not in "else if indexPath.row == 2"!!!
switch segment {
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier("CellTwo", forIndexPath: indexPath) as CellTwo
/* ... */
return cell
case 1:
let cell = tableView.dequeueReusableCellWithIdentifier("CellThree", forIndexPath: indexPath) as CellThree
/* ... */
return cell
default: //set your last segment case in "default:", not in "case 2:"!!!
let cell = tableView.dequeueReusableCellWithIdentifier("CellFour", forIndexPath: indexPath) as CellFour
/* ... */
return cell
}
}
//No need for a fictive "return cell" with this code!!!
}
If segment
is not an optional, thanks to tuples, you can even reduce the previous code to this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch (indexPath.row, segment) {
case (0, _):
let cell = tableView.dequeueReusableCellWithIdentifier("CellZero", forIndexPath: indexPath) as UITableViewCell
/* ... */
return cell
case (1, _):
let cell = tableView.dequeueReusableCellWithIdentifier("CellOne", forIndexPath: indexPath) as CellOne
/* ... */
return cell
case (2, 0):
let cell = tableView.dequeueReusableCellWithIdentifier("CellTwo", forIndexPath: indexPath) as CellTwo
/* ... */
return cell
case (2, 1):
let cell = tableView.dequeueReusableCellWithIdentifier("CellThree", forIndexPath: indexPath) as CellThree
/* ... */
return cell
default: //case (2, 2)
let cell = tableView.dequeueReusableCellWithIdentifier("CellFour", forIndexPath: indexPath) as CellFour
/* ... */
return cell
}
}
You mustn't return nil from cellForRowAtIndexPath. You always should return a valid cell.
var cell: UITableViewCell!
This line of code doesn't create any cell, it just a UITableViewCell variable with nil content, you have to assign a value to it:
var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
return cell
You are only declaring the last var cell: UITableViewCell!
- you are not initialising it. You need to do something like
var cell = UITableViewCell(style: someStyle, reuseIdentifier: someID)
return cell
You need to declare the cell before your if...then
logic, then return it after. You don't have to initialize the cell if you use var
:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell!
if indexPath.row == 0 {
cell = tableView.dequeueReusableCellWithIdentifier("imageCell", forIndexPath: indexPath) as UITableViewCell
// ...
} else if indexPath.row == 1 {
cell = tableView.dequeueReusableCellWithIdentifier("segmentCell", forIndexPath: indexPath) as UITableViewCell
// ...
} else if indexPath.row == 2 {
// ...
}
return cell
}
(Just make sure you catch all cases - if your return cell without initializing you'll get a runtime error.)