Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enum class in swift

Im trying to create an enum class with a type and a function that returns all the types.

Initially I have my enum in my object class and a function that returns these as an array:

class someClass: Mappable {

enum Type: Int {
    case A = 0
    case B = 1
    case C = 2
        }
    }
}

func getAllTypes() -> [Type] {
    return [Type.A, Type.B, Type.C]
}
}

The reason i want to extract this out of my object class is because this type is also used in other classes and i don't want to duplicate any unnecessary code.

I can manage to subclass the enum but not the function that returns all the types in an array.

Any help will be appreciated.

like image 247
Jack Of Diamonds Avatar asked Oct 27 '25 10:10

Jack Of Diamonds


2 Answers

Initialize all using an executed-one-time-only closure and AnyGenerator

@vacawama showed how to initialize the all array in a generalized manner using an executed-one-time-only closure in combination with the failable init(rawValue:) initialer of enum's. A slight variation of the method in the fore mentioned answer is to exchange the explicit while loop and array appending with an AnyGenerator:

enum Type: Int {
    case A = 0, B, C, D, E, F, G, H

    static let all: [Type] = {
        var rValue = 0
        return AnyGenerator<Type> {
            defer { rValue += 1 }
            return Type(rawValue: rValue)
        }.map{$0}
    }()
}

print(Type.all) 
    // [Type.A, Type.B, Type.C, Type.D, Type.E, Type.F, Type.G, Type.H]

This works under the condition that rawValue's are simply ++ increasing (0, 1, 2, ...).


Initialize all by conforming the enum to SequenceType

As another alternative, since your rawValue's are integer-wise sequential (++), you could let your enum conform to SequenceType, in which case the array of all cases can be easily generated simply by using .map

enum Type: Int, SequenceType {
    case A = 0, B, C, D, E, F, G, H
    
    init() { self = A } // Default (first) case intializer
    
    /* conform Type to SequenceType (here: enables only 
       simple (self.rawValue)...last traversing) */
    func generate() -> AnyGenerator<Type> {
        var rValue = self.rawValue
        return AnyGenerator {
            defer { rValue += 1 }
            return Type(rawValue: rValue)
        }
    }
    
    /* use the fact that Type conforms to SequenceType to neatly
     initialize your static all array */
     static let all = Type().map { $0 }
}

print(Type.all) 
    // [Type.A, Type.B, Type.C, Type.D, Type.E, Type.F, Type.G, Type.H]

Applying this conformance only to initialize the static all array is possibly overkill, but a plausible alternative in case you'd like to be able to able to use other aspects of your enum conforming to SequenceType

for typeCase in Type() {
    // treat each type ...
    print(typeCase, terminator: " ")
} // A B C D E F G H

for caseFromEAndForward in Type.E {
    print(caseFromEAndForward, terminator: " ")
} // E F G H

Using flatMap to initialize cases based on a range of rawValue's

Finally, as a variation of @appzYourLife neat solution, in case you have very many cases, you can use a flatMap operation on the range of rawValue's to initialize the static allValues array, e.g.

enum Type: Int {
    case A = 0, B, C, D, E, F, G, H
    static let all = (A.rawValue...H.rawValue)
       .flatMap{ Type(rawValue: $0) }
}

print(Type.all) 
    // [Type.A, Type.B, Type.C, Type.D, Type.E, Type.F, Type.G, Type.H]

There's, however, not really any practical use for this method as the general size methods (@vacawama:s or the SequenceType above) would always be preferable for enums of many cases. The possibly use case I can see for this is if the rawValue's of the different cases are sequential but not simply by ++, e.g. if the rawValue's are used for some bitmasking

// ...
case A = 0, B = 2, C = 4, D = 8, E = 16, F = 32, G = 64, H = 128

The method above would use a method of brute-forcing through the range of rawValue's, where a minority will actually correspond to actual cases. Somewhat wasteful, but since it's a one-time static initialization, that shouldn't really be an issue.

like image 195
dfrib Avatar answered Oct 29 '25 00:10

dfrib


Why don't you simply add a static property to your enum Type?

enum Type: Int {
    case A = 0, B, C
    static let all = [A, B, C]
}
like image 39
Luca Angeletti Avatar answered Oct 28 '25 22:10

Luca Angeletti