Alan
Alan

Reputation: 1142

Storing a type in a variable?

So I was wondering about whether I could save a type in a variable, to be used later on in the same function.

My code is as follows:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let object = array.item(at: indexPath.row) else {
        fatalError("Could not retrieve the table object")
    }

    if object.displayOnLeft {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: LeftSidedCell.className, for: indexPath) as? LeftSidedCell else {
            fatalError("Could not dequeue the left sided cell")
        }
        cell.object = object
        return cell
    } else {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: RightSidedCell.className, for: indexPath) as? RightSidedCell else {
             fatalError("Could not dequeue the right sided cell")
        }
        cell.object = object
        return cell
    }
}

But I figured that this is actually quite clunky, since the contents inside the if and the else are essentially the same, with just the type of cell differing.

I ideally want an algorithm that is basically:

var type
if object.displayOnLeft {
   type = LeftSidedCell
} else {
   type = RightSidedCell
}

//Dequeue Cell with type

I understand there are a few issues here, firstly, I cannot declare a variable without a type, and i'm not sure what type to assign it to at first. Second, retrieving the type of class has not been fruitful either.

I have tried storing it as a property in the Object, as well as returning it in a function such as this in my custom object as well as some variations of the following:

func getTypeOfCell<T:TranslationCellProtocol>() -> T.Type {
    if displayOnLeft {
        return LeftSidedCell.self
    } else {
        return RightSidedCell.self
    }
}

Anyway, I'm not sure if this is possible or if i have a fundamental misunderstanding of a concept, but any help would be much appreciated.

Thank you.

Upvotes: 3

Views: 117

Answers (3)

matt
matt

Reputation: 535232

As long as LeftSidedCell and RightSidedCell have a common superclass — say, MySidedCell — you can store them in a variable of type MySidedCell.Type:

let cellType : MySidedCell.Type = LeftSidedCell.self

You can later just test that value with == to see which cell type it is.

if cellType == LeftSidedCell.self {

Upvotes: 2

Au Ris
Au Ris

Reputation: 4659

To mind mind you are clogging your code with so many optional checks and those fataError calls. By the time cellForRow is called you should already be sure that your datasource is correct. So there is no need to optionally unwrap your data and table view cells at this point as the app will crash anyway if the data are incorrect.

E.g. do a check if your array has no items or items are somehow invalid before numberOfRowsInSection is called, if your data is not correct return 0 number of items and cellForRow will not get called with that faulty data.

Regarding code cleaniness, this would do for me:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let object = array[indexPath.row]
    let cell: UITableViewCell

    if object.displayOnLeft {
        cell = tableView.dequeueReusableCell(withIdentifier: "LeftSidedCellIdentifier", for: indexPath) as! LeftSidedCell
    } else {
        cell = tableView.dequeueReusableCell(withIdentifier: "RightSidedCellIdentifier", for: indexPath) as! RightSidedCell
    }

    cell.object = object
    return cell
}

Upvotes: 1

mag_zbc
mag_zbc

Reputation: 6982

First, write a protocol that implements className() method (or any methods and properties you will use for both cell classes) and have both your cell classes conform to it

protocol YourCellProtocol {
    var object : YourObjectClass? { get set }
    static func className() -> String
}

class LeftSidedCell : YourCellProtocol {...)
class RightSidedCell : YourCellProtocol {...}

Then you will be able to do something like that

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let object = array.item(at: indexPath.row) else {
        fatalError("Could not retrieve the table object")
    }

    var type : YourCellProtocol.Type
    if object.displayOnLeft {
        type = LeftSidedCell.self
    } else {
        type = RightSidedCell.self
    }

    let cell = tableView.dequeueReusableCell(withIdentifier: type.className, for: indexPath)
    if let yourCell = cell as? YourCellProtocol
    {
        yourCell.object = object
    }

    return cell
}

Upvotes: 2

Related Questions