Nikita Rysin
Nikita Rysin

Reputation: 29

How to create array of types Swift

So, my thought are:

I have different classes of UITableViewCell: CustomCell1, CustomCell2, CustomCell3

I have UITableView, and I need to add them through cellForRowAt, but there can be multiple cell of any type.

For example, table should contain this: CustomCell2, CustomCell2, CustomCell3, CustomCell1, CustomCell1, also there is Bool variable, and if it's true, them CustomCell1 should be added, if not then CustomCell3

Is there any way of creating array of this cell types? Like

arrayOfTypes = [CustomCell2, CustomCell2, CustomCell3, CustomCell1, CustomCell1, boolVariable ? CustomCell1 : CustomCell3]

So then in cellForRowAt I can call like this:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let type = arrayOfTypes[indexPath.row]
        switch type {
        case is CustomCell1:
        ...
        case is CustomCell2:
        ...
        case is CustomCell3:
        ...
        default:
        ...
        }
}

Or maybe there's more convenient way of doing such a thing?

So now in project I do this:

enum CustomCellType {
    case CustomCell1
    case CustomCell2
    case CustomCell3
}

class CellItem {
    var cellType: CustomCellType

    init(CellType type: CustomCellType) {
        self.cellType = type
    }
}

...
class WorkingWithData: UITableViewDataSource, UITableViewDelegate {

    var tableData = [CellItem]()

    override func viewDidLoad() {
        fillCells()
    }

    func fillCells() {
        let cellItem = CellItem(CellType: .CustomCell1)
        tableData.append(cellItem)
        let cellItem2 = CellItem(CellType: .CustomCell3)
        tableData.append(cellItem2)
    }

    ...
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let item = tableData[indexPath.row]
        switch item.cellType {
        case .CustomCell1:
        //dequeuereusablecell
        case .CustomCell2:
        //dequeuereusablecell
        case .CustomCell3:
        //dequeuereusablecell
        default:
        ...
        }
    }
}

Upvotes: 0

Views: 190

Answers (1)

Samps
Samps

Reputation: 1049

Answer for your first question:

let cellTypes: [UITableViewCell.Type] = [UITableViewCell.self]
    let type = cellTypes[indexPath.row]
    switch type {
    case is UITableViewCell.Type:
        break
    default:
        break
}

Another way:

enum CustomCellType: Int {
    // enum names in swift starts with lower case
    case customCell1
    case customCell2
    case customCell3

    var dequeType: UITableViewCell.Type {
        switch self {
        case .customCell1: return CustomCellType.self
        case .customCell2: return CustomCellType2.self
        case .customCell3: return CustomCellType3.self
        }
    }
}

// Add extension to register and deque cells with type
public extension UITableView {
    func register<T: UITableViewCell>(_ cellType: T.Type) {
        register(cellType, forCellReuseIdentifier: String(describing: cellType))
    }
    func dequeue<T: UITableViewCell>(_ cellType: T.Type, for indexPath: IndexPath) -> T {
        guard let cell = dequeueReusableCell(
            withIdentifier: String(describing: cellType),
            for: indexPath
        ) as? T else {
            fatalError("Unable to dequeue cell for \(cellType)")
        }
        return cell
    }
}

// ––––––––– Inside Class where the tableview exists –––––––––
// Register cells
func registerCells() {
    CustomCellType.allCases.forEach({ tableView.register($0.dequeType) })
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cellType = CustomCellType(rawValue: indexPath.row) else {
        fatalError("Your message")
    }

    let cell = tableView.dequeue(cellType.dequeType, for: indexPath)
    // Cell is now with concrete type
    return cell
}

Upvotes: 1

Related Questions