Reputation: 611
I would like to add checkmarks to my Table View cells. I would think to just implement cell.accessoryType = UITableViewCellAccessoryCheckmark
in my didSelectRowAt
method, but I can't get this to work when using a custom UITableViewCell
subclass.
Custom cell:
class TableCell: UITableViewCell {
@IBOutlet weak var tableLabel: UILabel!
var arrayOneToDisplay:ArrayOne?
let arrayOne = ArrayOne()
func displayTable(_ currentArrayOne:ArrayOne) {
// Keep a reference to the cell
arrayOneToDisplay = currentArrayOne
// Get the Table Cells data
var tableCell = arrayOne.tableCells
// Set the instructionLabel
tableLabel.text = currentArrayOne.tableCells![0]
}
ViewController:
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Make sure the array contains at least 1 item
guard arrayOne.count > 0 else {
return 0
}
// Return the number of items for this array
let currentArrayOne = arrayOne[currentArrayOneIndex!]
if currentArrayOne.tableCells != nil {
return currentArrayOne.tableCells!.count
}
else {
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Get a cell
let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell", for: indexPath) as! TableCell
// Get the instruction that the tableView is asking about
let tableLabel = cell.tableLabel
if tableLabel != nil {
let currentArrayOne = arrayOne[currentArrayOneIndex!]
if currentArrayOne.tableCells != nil && indexPath.row < currentArrayOne.tableCells!.count {
// Set the text for the label
tableLabel!.text = currentArrayOne.tableCells![indexPath.row]
}
}
// Return the cell
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
When I try to implement cell.accessoryType
in the ViewController, Xcode doesn't recognize accessoryType
. I believe it's because my methods are for UITableView
and not UITableViewCell
, so the added wrinkle of using a custom cell is causing some confusion for me. Any guidance is much appreciated!
Upvotes: 0
Views: 1032
Reputation: 285200
Sorry, your approach is completely wrong. Never use a view as a data source type. Don't.
Create a model, this is a simple example with name
and isSelected
properties
struct Model {
let name : String
var isSelected = false
}
and in controller ViewController
declare a data source array containing Model
instances
var arrayOne = [Model(name: "Foo"), Model(name: "Bar"), Model(name: "Baz")]
In the extension in numberOfRows
just return the number of items in the array (your guard
expression makes no sense at all), in cellForRow
set the checkmark depending on isSelected
and in didSelect
toggle the isSelected
property and reload the row.
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayOne.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Get a cell
let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell", for: indexPath) as! TableCell
// Get the item of the data source array
let item = arrayOne[indexPath.row]
// update the view
cell.tableLabel = item.name
cell.accessoryType = item.isSelected ? .checkmark : .none
// Return the cell
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// toggle isSelected of the row in the model
arrayOne[indexPath.row].isSelected.toggle()
// reload the row to update the view
tableView.reloadRows(at: [indexPath], with: .none)
}
}
In the custom cell declare only the outlet, nothing else
class TableCell: UITableViewCell {
@IBOutlet weak var tableLabel: UILabel!
}
The benefit of this approach is that model and view are always in sync.
Upvotes: 1
Reputation: 13284
You should set your accessoryType
in the cellForRowAt
method, try to rewrite it as this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell", for: indexPath) as! TableCell
cell.accessoryType = .checkmark
guard let arrayOneIndex = currentArrayOneIndex, arrayOneIndex < arrayOne.count else { return cell }
let currentArrayOne = arrayOne[arrayOneIndex]
guard let tableCells = currentArrayOne.tableCells, indexPath.row < tableCells.count else { return cell }
cell.tableLabel.text = tableCells[indexPath.row]
return cell
}
Upvotes: 0
Reputation: 3219
Not sure to understand what you try to do. The usual way for table view is not to save tableviewcell in array. The model-view-controller (MVC) way is to save the contents of the cells (text, images, checkedOrNotChecked) in an array of struct or object inside the viewcontroller (the array is the model). Then in CellForRow, set the content of the cell with the array[indexPath.row] element and if checkedOrNotCheckindicator set cell.accessoryType to checkmark (the cell is the view). In didSelectRow , you just set the checkOrNotCheck indicator of indexPath.row element and then reload the table view or just reload the cell at indexPath. Thé ViewController is the controller in MVC
Upvotes: 0