First, stop hard-coding strings

There is a variety of opinions on hard-coding. When it comes to strings, mine is simple. Hard-coding strings is bad and should be avoided. Why? Because tyops. Uh... typos. Especially with string we have to repeat, over and over, and oevr. Each time is yet another opportunity for a tyop to creep in and crash our app.

Sure, we can copy-paste that string.

But first of all, it's annoying.

Second, the day we have to update it, you'll have to do it all over again.

And not forget an occurence.

Unless you run a project-wide search and replace.

But maybe you also used the same string somewhere else, for something unrelated, and don't want to change that one ?

Okay, let's scope our search and replace.

Or do it one by one...

... Oh dear...

Isn't that what variables, constants and enums are for? What can we do then?

Static constant in the cell's class

We'll use a constant! A static constant! Write once, use everywhere, update once, and get compiler auto-complete and spell-checking for free! Neat!

class MyCell: UITableViewCell {
    static let identifier = "MyCellIdentifier"
    
    ...	// The rest of your cell's properties, methods & overrides
}
...

extension MyViewController: UITableViewDataSource {
    ...
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: MyCell.identifier) as? MyCell else {
            // I have yet to figure out what I should do here
            return MyCell()
        }
        ...	// Do your cell setup here
        return cell
    }
}

...

This method, however, requires us to remind ourselves to give our different cells' classes unique identifiers, manually.

It's one more thing to remember to do, and to actually do.

Each and every time.

It's also one more thing to name, and as the saying goes "There are only two hard things in Computer Science: cache invalidation and naming things."

But... wait. Isn't there something we already have to name, each and every time we create a new class of cell? And uniquely at that? With a compiler-enforced uniqueness? Yes, indeed! The class itself!

So let's do one of my favorite things, as a programmer: less.

Using the class name as the identifier

...

extension MyViewController: UITableViewDataSource {
    ...
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: MyCell.self)) as? MyCell else {
            // I have yet to figure out what I should do here
            return MyCell()
        }
        ...	// Do your cell setup here
        return cell
    }
}

...
Yes, that's right; it's the little bonus I snuck in the recap of my post on handling cell selection

A bit shorter, and one less thing to thing about! This is my favorite. Short, simple, and clear. Sure, we could extend the UITableViewCell and UICollectionViewCell classes with a static computed property we would name cellIdentifier, returning String(describing: self). However, while I wouldn't call extending native classes a bad practice, I've been burnt by that already, and am not a great fan. So, do what you will, and to each his or her own :-)

Conclusion

Now, sadly, that doesn't take care of the Storyboard part, and we still have to write down that identifier by hand if we add the cells to our UITableViews and UICollections through that. But still, it's progress!

P.S. Alternatively, we could simply use Reusable. But then we'd have to make sure our Storyboards and XIBs are correctly named ¯\_(ツ)_/¯