I have some custom UITableViewCell,and would using some of them randomly. But after I register them ,it will crashed in tableView(_cellForRowAt:).
Here is my code:
in viewDidLoad method
tableView.register(CustomACell.self, forCellReuseIdentifier: "Identifier")
tableView.register(CustomACell.self, forCellReuseIdentifier: "Identifier")
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let model = dataSource[indexPath.row]
if let type = model.type {
switch type {
case .A:
let cell = tableView.dequeueReusableCell(withIdentifier: MyIdentifier) as! CustomACell
cell.assgin(message: model)
return cell
case .B:
let cell = tableView.dequeueReusableCell(withIdentifier: MyIdentifier) as! CustomBCell
cell.assgin(message: model)
return cell
}
}
let cell = tableView.dequeueReusableCell(withIdentifier: MyIdentifier) as! CustomACell
cell.assgin(message: model)
return cell
}
If I register both ,it will crashed at case .A. If I won't, some of them would crash at tableView.dequeueReusableCell.
Here is one of the console error info:
Could not cast value of type 'TM.CustomACell' (0x10bb40940) to 'TM.CustomBCell' (0x10bb40578).
Change the CellReuseIdentifiers. You use same for both custom cells. Use diffrent identifires for diffrent cells.
var nibName = UINib(nibName: "Identifier1", bundle: nil)
self.tableView.register(nibName, forCellReuseIdentifier: "Identifier")
nibName = UINib(nibName: "Identifier2", bundle: nil)
self.tableView.register(nibName, forCellReuseIdentifier: "Identifier2")
Then change the cellForRowAt, try following code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let model = dataSource[indexPath.row]
if let type = model.type {
switch type {
case .A:
let cell = tableView.dequeueReusableCell(withIdentifier: "Identifier1") as! CustomACell
cell.assgin(message: model)
return cell
case .B:
let cell = tableView.dequeueReusableCell(withIdentifier: "Identifier2") as! CustomBCell
cell.assgin(message: model)
return cell
default :
let cell = tableView.dequeueReusableCell(withIdentifier: "Identifier1") as! CustomACell
cell.assgin(message: model)
return cell
}
}
}
if you created a separate Nib, then you can register else no need to register
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->UITableViewCell{
var cell = UITableViewCell(style: .default, reuseIdentifier: "pgIdentifier")
if (XXX == true) {
let pgtcell = tableView.dequeueReusableCell(withIdentifier: "indetifier", for: indexPath) as! CustomCell1
} else {
let pgtcell = tableView.dequeueReusableCell(withIdentifier: "indetifier", for: indexPath) as! MyCustomCell1
}
}
Related
I have a table view with 2 different cells. Both cells conform to same protocol "WorkoutCellProtocol" and I want to avoid rewriting same code during dequeuing. Probably there will more cells in the future, but each will conform to same protocol.
First cell is WorkoutCell with identifier: "WorkoutTableViewCell"
Second cell is CardioCell with identifier: "CardioTableViewCell"
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: WorkoutCellProtocols!
cell.delegate = self
cell.editableRowBorders = colorEditable
cell.numberOfCell = indexPath.row
cell.numberOfExercise = indexPath.section
cell.configureTextFields(model:
exercises[indexPath.row])
if data[indexPath.row].category == "Cardio" {
cell = tableView.dequeueReusableCell(withIdentifier: "CardioTableViewCell", for: indexPath) as! CardioTableViewCell
return cell as! CardioTableViewCell
} else {
cell = tableView.dequeueReusableCell(withIdentifier: "WorkoutTableViewCell") as! WorkoutTableViewCell
return cell as! WorkoutTableViewCell
}
}
When I try to do this in this way, so assign properties only once at the top, before assigning a class types I get "Unexpectedly found nil while implicitly unwrapping an Optional value".
Dequeue your cell first, then configure it:
var cell: WorkoutCellProtocols
if data[indexPath.row].category == "Cardio" {
cell = tableView.dequeueReusableCell(withIdentifier: "CardioTableViewCell", for: indexPath) as! WorkoutCellProtocols
} else {
cell = tableView.dequeueReusableCell(withIdentifier: "WorkoutTableViewCell") as! WorkoutCellProtocols
}
cell.delegate = self
cell.editableRowBorders = colorEditable
cell.numberOfCell = indexPath.row
cell.numberOfExercise = indexPath.section
cell.configureTextFields(model: exercises[indexPath.row])
return cell
I'm assuming that your protocol is declared like this:
protocol WorkoutCellProtocols: UITableViewCell {
...
}
You can't do what you are trying to do with any implicitly unwrapped optional. Try moving the assignments down below the if block and type the cell to the protocol like this
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: WorkoutCellProtocols!
if data[indexPath.row].category == "Cardio" {
cell = tableView.dequeueReusableCell(withIdentifier: "CardioTableViewCell", for: indexPath) as! CardioTableViewCell
} else {
cell = tableView.dequeueReusableCell(withIdentifier: "WorkoutTableViewCell") as! WorkoutTableViewCell
}
guard let workoutCell = cell as WorkoutCellProtocols! else { fatalError("Unexpected cell type") }
workoutCell.delegate = self
workoutCell.editableRowBorders = colorEditable
workoutCell.numberOfCell = indexPath.row
workoutCell.numberOfExercise = indexPath.section
workoutCell.configureTextFields(model: exercises[indexPath.row])
return workoutCell
}
I am trying to use a three tableviews in a XIB. I've created a custom UITableViewCell class, however when I am trying to use it, comes up with an error saying..."Unexpectedly found nil while unwrapping an Optional value". I have tried regist
internal func tableView(_ tableView: UITableView, cellForRowAt
indexPath: IndexPath) -> UITableViewCell{
if tableView == resultsTable {
if savedWheelsArray.count > 0 {
self.resultsTable.register(accessoryCellTableViewCell.self, forCellReuseIdentifier: "accessoryCell")
let cell = tableView.dequeueReusableCell(withIdentifier: "accessoryCell" , for: indexPath) as! accessoryCellTableViewCell
//let wheel = savedWheelsArray[indexPath.row]
cell.AccessoryTitle.text = "WTF"
cell.AcessoryImage.image = UIImage(named: "history")
print("set up searched wheels cell")
return cell
}
else {
let cellIdentifier : String = "accessoryCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! accessoryCellTableViewCell
cell.AccessoryTitle.text = "no saved wheels"
cell.AcessoryImage.image = UIImage(named: "history")
print("no saved wheels found")
return cell
}
}
else {
}
return UITableViewCell()
}
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
}
I have a few custom tableview cells which all have a different unib and different classes and want to reorder the cells and persistent safe their reordered position.
I have registered every cell and UINib in my TablevViewController
let test1Nib = UINib(nibName: "Test1", bundle: nil)
myTableView.register(overViewNib, forCellReuseIdentifier: "Test1")
let test2Nib = UINib(nibName: "Test2", bundle: nil)
myTableView.register(todoNib, forCellReuseIdentifier: "Test2")
let test3Nib = UINib(nibName: "Test3", bundle: nil)
myTableView.register(financeNib, forCellReuseIdentifier: "Test3")
let test4Nib = UINib(nibName: "Test4", bundle: nil)
myTableView.register(upcomingNib, forCellReuseIdentifier: "Test4")
I have then added the UINibs to my testArray:
testArray.append(test1Nib)
testArray.append(test2Nib)
testArray.append(test3Nib)
testArray.append(test4Nib)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = myTableView.dequeueReusableCell(withIdentifier: "Test1", for: indexPath)
return cell
} else if indexPath.row == 1 {
let cell = myTableView.dequeueReusableCell(withIdentifier: "Test2", for: indexPath)
return cell
} else if indexPath.row == 2 {
let cell = myTableView.dequeueReusableCell(withIdentifier: "Test3", for: indexPath)
return cell
} else {
let cell = myTableView.dequeueReusableCell(withIdentifier: "Test4", for: indexPath)
return cell
}
}
The moveRowAt: function is doing as expected
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let movedObject = self.testArray[sourceIndexPath.row]
testArray.remove(at: sourceIndexPath.row)
testArray.insert(movedObject, at: destinationIndexPath.row)
NSLog("%#", "\(sourceIndexPath.row) -> \(destinationIndexPath.row)")
}
At this point I got a few issues
1. after reorder the cells are reloaded since I have fixed their index path to a static value and well now the questions is how can I prevent
them to reorder them selfs and 2. How can I persist this order
I hope I can find help here - I researched the web a lot now but nothing suites my needs.
Hope I can find a solution or some links or code snippets.
thanks a lot!
You should not force the check of indexPath row to decide which cell to load.
You should get their type and then switch into it. something like:
let type = testArray[indexPath.row]
switch type {
case Type1:
let cell = myTableView.dequeueReusableCell(withIdentifier: "Test1", for: indexPath)
return cell
case Type2:
let cell = myTableView.dequeueReusableCell(withIdentifier: "Test2", for: indexPath)
return cell
}
How you set this type depends on you. There are several ways to do this, pick your favorite.
Actually I am trying to add CollectionView in TableViewCell but I am not able to handel it as you can see in case of adding TableView in TableViewCell works fine but in case of Collection view it shows error.
See the screen shot for your reference.
Can you please suggest how to fix this error.
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if (dataArray[indexPath.row]["type"].string == "Traffic") {
tableView.registerClass(TrafficCollectionViewCell.self, forCellReuseIdentifier: "TrafficCollectionView")
let TrafficCell = tableView.dequeueReusableCellWithIdentifier("TrafficCollectionView", forIndexPath: indexPath) as! TrafficCollectionViewCell
print("im in Traffic Cell")
TrafficCell.TrafficArray = dataArray[indexPath.row]["detail"].arrayObject!
TrafficCell.TrafficCollectionView.reloadData()
TrafficCell.TrafficViewController = self
return TrafficCell
}
else if (dataArray[indexPath.row]["type"].string == "News") {
tableView.registerClass(NewsTableViewCell.self, forCellReuseIdentifier: "NewsTableViewCell")
let NewsCell = tableView.dequeueReusableCellWithIdentifier("NewsTableViewCell", forIndexPath: indexPath) as! NewsTableViewCell
print("Im in News Cell")
NewsCell.NewsArray = dataArray[indexPath.row]["detail"].arrayObject!
NewsCell.NewsTableView.reloadData()
NewsCell.NewsTableViewController = self
return NewsCell
}
else if (dataArray[indexPath.row]["type"].string == "Category") {
tableView.registerClass(CategoryTableViewCell.self, forCellReuseIdentifier: "CategoryTableViewCell")
let CategoryCell = tableView.dequeueReusableCellWithIdentifier("CategoryTableViewCell", forIndexPath: indexPath) as! CategoryTableViewCell
print("Im in Category Cell")
CategoryCell.CategoryArray = dataArray[indexPath.row]["detail"].arrayObject!
CategoryCell.CategoryTableView.reloadData()
CategoryCell.CategoryTableViewController = self
return CategoryCell
}