Reputation: 9012
Is it possible to implicitly cast an enum to a string in Swift?
As a concrete example, consider the following enum representing a UITableViewCell
identifier:
enum TableViewCellIdentifier : String {
case Basic = "Cell"
}
Then we may want to deque a cell with that identifier...
let cell = tableView.dequeueReusableCellWithIdentifier(TableViewCellIdentifier.Basic.rawValue, forIndexPath: indexPath)
The fact that everywhere we use this pattern we need to use .rawValue
is particularly annoying.
Is there any protocol I can make the enum conform to in order to gain this functionality? I've tried looking at StringLiteralConvertible
but that is for constructing a value rather than extracting it.
Upvotes: 0
Views: 350
Reputation: 150705
I would do this slightly differently to the other answer.
First, I would declare a protocol and a protocol extension
protocol TableViewRowReturnable {
typealias RowIdentifier: RawRepresentable
}
extension TableViewRowReturnable where Self: UITableViewDataSource, RowIdentifier.RawValue == String {
func dequeueReuesableCellWithIdentfier(identifier: RowIdentifier, fromTableView tableView: UITableView, forIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return tableView.dequeueReusableCellWithIdentifier(identifier.rawValue, forIndexPath: indexPath)
}
}
I'm providing a custom implementation for the case of the implementing type being a UITableViewDatasource
because that's the type that returns actually deals with the row.
Now make the DataSource conform to the protocol by providing the enum containing the cell identifiers:
extension ViewController: UITableViewDataSource, TableViewRowReturnable {
enum RowIdentifier: String {
case RedCell = "RedCell"
case BlueCell = "BlueCell"
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell
switch (indexPath.row % 2) {
case 0:
cell = dequeueReuesableCellWithIdentfier(.RedCell, fromTableView: tableView, forIndexPath: indexPath)
default:
cell = dequeueReuesableCellWithIdentfier(.BlueCell, fromTableView: tableView, forIndexPath: indexPath)
}
cell.textLabel?.text = "Your value here"
return cell
}
}
This keeps your enum with the cell identifiers nicely contained in the function that uses it. Also, the default implementation is only available it types that are declared as implementing the protocol, rather than adding it to every instance of UITableView
Upvotes: 1
Reputation: 285240
In the WWDC 2015 session "Swift in Practice" the presenter suggested to use an extension for exactly this purpose
enum TableViewCellIdentifier : String {
case Basic = "Cell"
}
extension UITableView {
func dequeueReusableCellWithTableViewCellIdentifier(identifier: TableViewCellIdentifier, forIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return self.dequeueReusableCellWithIdentifier(identifier.rawValue, forIndexPath:indexPath)
}
}
Then you can call the function
let cell = tableView.dequeueReusableCellWithTableViewCellIdentifier(.Basic, forIndexPath: indexPath)
Upvotes: 1