ReyHaynes
ReyHaynes

Reputation: 3102

Accessing dot notated enums from a class in Swift

I'm still fairly new to SwiftUI & Swift (from Javascript background) and I am working on creating a clone calculator app.

My CalculatorView currently has a button layout which is passed in to CalculatorActions and does what it needs to do to update the CalculatorView display.

// CalculatorView.swift 

// buttons = View layout with enum defined buttons
let buttons: [[Calculator]] = [
    [.ac, .plusMinus, .percent, .divide],
    [.seven, .eight, .nine, .multiply],
    [.four, .five, .six, .minus],
    [.one, .two, .three, .plus],
    [.zero, .period, .equal]
]

// var body
// ...
ForEach(buttons, id: \.self) { row in
    HStack(spacing: sizing.spacing) {
        ForEach(row, id: \.self) { button in
            Button(action: {
                actions.updateDisplay(button: button)
            }, label: {
                ButtonView(button: button, sizing: sizing)
            })
        }
    }
}
// ...

I have an enum I am using for my Calculator model like so:

// Calculator.swift (Enum Calculator Model)

enum Calculator: String {
    case ac, clear, plusMinus, percent, divide
    case seven, eight, nine, multiply
    case four, five, six, minus
    case one, two, three, plus
    case zero, period, equal

    var label: String {
        switch (self) {
            case .zero: return "0"
            case .one: return "1"
            case .two: return "2"
            case .three: return "3"
        // ...

I access these enums through the class in a separate file that I have with a controller where I often do comparisons or to access the label of whatever button was passed in like so:

// CalculatorActions.swift (Calculator Controller)

class CalculatorActions: ObservableObject {
    // ...
    func updateDisplay(button: Calculator) -> Void {
        // Clear
        if button == Calculator.ac {
            self.resetEverything()
            self.lastButtonPressed = button
            return
        }
    
        if button == Calculator.plusMinus {
        // ...
        self.append(Calculator.one.label)

I would love to clean up this and have the CalculatorActions controller class, which is in a separate file, essentially do enum comparisons like this

// CalculatorActions.swift (Calculator Controller)

class CalculatorActions: ObservableObject {
    // ...
    func updateDisplay(button: Calculator) -> Void {
        // Clear
        if button == .ac {
            self.resetEverything()
            self.lastButtonPressed = button
            return
        }
    
        if button == .plusMinus {
        // ...
        self.append(.one.label)

but for obvious reasons, you can't extend a class with an enum.

Essentially, within CalculatorActions.swift, I want to be able to use enum from Calculator.swift .plusMinus instead of Calculator.plusMinus.

If possible or not, please school me.

Upvotes: 0

Views: 689

Answers (2)

pawello2222
pawello2222

Reputation: 54486

Swift can automatically infer types

In your function:

func updateDisplay(button: Calculator) { // no need to specify `Void` explicitly 
    // Clear
    if button == .ac { // you can skip `Calculator` and use `.ac`, Swift knows that button is of type `Calculator`
        resetEverything()
        lastButtonPressed = button // no need to use self (individual preference)
        // you don't need to return from `Void` function
    }

    if button == .plusMinus { // again, you can replace `Calculator.plusMinus` with `.plusMinus`
    // ...
    self.append(.one.label) // `append` accepts a `string` parameter, you may need to make it accept `Calculator` parameter instead and call it like `append(.one)`
}

Basically you can use .plusMinus instead of Calculator.plusMinus wherever Swift is able to infer the type automatically. Which can be when comparing .plusMinus with another Calculator variable, passing the Calculator parameter...

Just remember Swift needs to know you're passing the Calculator variable.


Note that you can specify a rawValue directly:

enum Calculator: String {
    case one = "1", two = "2", three = "3", plus = "+"
    ...

    var label: String {
        rawValue
    }
}

I'd recommend also renaming Calculator to something more descriptive. It's not a calculator, but a part of it (CalculatorItem, CalculatorButton...).

Upvotes: 1

Łukasz
Łukasz

Reputation: 805

Maybe it's an answer (as far I can understand question):

enum Calculator: String {
    case ac, clear, plusMinus, percent, divide
    case seven, eight, nine, multiply
    case four, five, six, minus
    case one, two, three, plus
    case zero, period, equal
    
    var label: String {
        return self.rawValue
    }
}

If you want assign some var to enum element, this var must have defined type:

var calc: Calculator
calc = .eight 

and if your append function is defined as

func append(_ calc: Calculator) {...}

you can call it:

append(.eight)

Upvotes: 1

Related Questions