DevB1
DevB1

Reputation: 1565

Swift: how to set property with an enum using String

I'm hitting an endpoint which returns a specific String as follows:

type: "event type A"

Depending on the event type I receive I need to set an icon in another part of the app. I wanted to do this using an enum. The element which contains the icon is declared in a class which subclasses UITableViewCell (HistoryTableViewCell) as follows:

private lazy var type: UIImageView = {
    let imageView = UIImageView()
    imageView.translatesAutoresizingMaskIntoConstraints = false
    imageView.contentMode = .scaleAspectFill
    imageView.tintColor = UIColor.darkGrey
    contentView.addSubview(imageView)
    return imageView
}()

So I want to set the image depending on the value retrieved from the API. I had set up the following enum:

enum EventType {
    case eventTypeA
    case eventTypeB
    case eventTypeC
    case eventTypeD
    case eventTypeE
    case eventTypeF
}

Then an event type variable:

var eventType: EventType {
    willSet {
        switch newValue {
        case .eventTypeA:
            type.image = #imageLiteral(resourceName: "eventA_icon")
        case .eventTypeB:
            type.image = #imageLiteral(resourceName: "eventB_icon")
        case .eventTypeC:
            type.image = #imageLiteral(resourceName: "eventC_icon")
        case .eventTypeD:
            type.image = #imageLiteral(resourceName: "eventD_icon")
        case .eventTypeE:
            type.image = #imageLiteral(resourceName: "eventE_icon")
        case .eventTypeF:
            type.image = #imageLiteral(resourceName: "EventF_icon")
            
        default:
            type.image = #imageLiteral(resourceName: "eventA_icon")
        }
    }
}

But this is where I came a little unstuck. How to set eventType with a value from the enum using the String I receive from the API response in an efficient manner.

So in the TableViewController (HistoryTableViewController) I did set up another switch method:

private func setEventType(data: HistoryTableViewController.History, cell: HistoryTableViewCell) {
    switch data.type {
    case "event type A":
        cell.eventType = .eventTypeA
    case "event type B":
        cell.eventType = .eventTypeB
    case "event type C":
        cell.eventType = .eventTypeC
    case "event type D":
        cell.eventType = .eventTypeD
    case "event type E":
        cell.eventType = .eventTypeE
    case "event type F":
        cell.eventType = .eventTypeF
    default:
        return
    }
}

History is defined as follows:

struct History {
    let type: String?
    ... // more  values here
}

And then I have a variable data as follows:

var data = [History]()

And I was calling my setEventTypeMethod like this:

setEventType(data: data[indexPath.row], cell: cell)

It works (!) but seems hideously inefficient and I'm sure there must be a more stable / effective way of handling this.

Upvotes: 1

Views: 618

Answers (2)

Joakim Danielson
Joakim Danielson

Reputation: 51973

You can let your enum have an associated value that is the string for each event type (I shortened the enum for clarity)

enum EventType: String {
    case eventTypeA = "event type A"
    case eventTypeB = "event type B"
    case eventTypeC = "event type C"
}

and then use it like this

private func setEventType(data: HistoryTableViewController.History, cell: HistoryTableViewCell) {
    guard let eventType = EventType(rawValue: data.type) else { return }
    cell.eventType = eventType
}

Another option if the event types are so similar named as in your code is to let the associated value to only be the unique part of the string and add a special init to extract that part

enum EventType: String {
    case a
    case b
    case c

    init?(eventType: String) {
        let value = eventType.sufix(1).lowercased()
        self.init(rawValue: value)
    }
}

Then this can be used to simplify your code a lot

private func setEventType(data: HistoryTableViewController.History, cell: HistoryTableViewCell) {
    guard let eventType = EventType(eventType: data.type) else { return }
    cell.eventType = eventType
}

var eventType: EventType {
    willSet {
        var imageName = "event\(newValue.rawValue.uppercased())_icon"
        type.image = imageLiteral(resourceName: imageName)
    }
}

Upvotes: 1

gcharita
gcharita

Reputation: 8337

You can modify your enum to use raw value of String, like this:

enum EventType: String {
    case eventTypeA = "event type A"
    case eventTypeB = "event type B"
    case eventTypeC = "event type C"
    case eventTypeD = "event type D"
    case eventTypeE = "event type E"
    case eventTypeF = "event type F"
}

Then your setEventType(data:cell:) will be simplified to this:

private func setEventType(data: HistoryTableViewController.History, cell: HistoryTableViewCell) {
    guard let type = data.type, let eventType = EventType(rawValue: type) else { return }
    cell.eventType = eventType
}

Upvotes: 1

Related Questions