Pass and Print All Cases in an Enum in Swift

Pass and print all cases in an enum in Swift

You can define a generic function which takes a type as argument which is CaseIterable and RawRepresentable:

func printEnumCases<T>(_: T.Type) where T: CaseIterable & RawRepresentable {
for c in T.allCases {
print(c.rawValue)
}
}

Usage:

enum MyEnum: String, CaseIterable {
case abc = "ABC"
case xyz = "XYZ"
}

printEnumCases(MyEnum.self)

How to pass an enum case into a function that uses 'if case' to check for a property's case

The answer of Shadowrun is a good start. Through the CasePaths library I found EnumKit, which was partially the inspiration for CasePaths. However it gives much simpler methods to compare cases. See my implementation below.

Using this library comes with some nice bonuses, it allows enums that have associated values to be made equatable by just comparing the cases and ignoring the values. This might not always be desired but come in quite handy in a lot of cases. I use it to compare ReSwift Actions with Associated values in my tests.

import Foundation
import EnumKit

class NonEquatableObject {
}

enum MyEnum: CaseAccessible { // <-- conform to CaseAccessible
case justACase
case numberCase(Int)
case stringCase(String)
case objectCase(NonEquatableObject)
}

let myArray: [MyEnum] = [.justACase, .numberCase(100), .stringCase("Hello Enum"), .justACase]

if case .justACase = myArray[0] {
print("myArray[0] is .justACase")
}

if case .numberCase = myArray[1] {
print("myArray[1] is .numberCase")
}

func checkCase(lhsCase: MyEnum, rhsCase: MyEnum) -> Bool {
if case lhsCase = rhsCase {
return true
} else {
return false
}
}

// Usage:
if checkCase(lhsCase: .justACase, rhsCase: myArray[0]) { //<-- allows to pass variables or just the cases (unfortunately not without associated value.)
print("myArray[0] is .justACase")
}

if case myArray[3] = myArray[0] { //<-- allows this here too
print("myArray[0] is .justACase")
}

// Bonus: Adding equatable if associated values are not equatable. Looking at the case only.
extension MyEnum: Equatable {
static func == (lhs: MyEnum, rhs: MyEnum) -> Bool {
lhs.matches(case: rhs)
}
}

if myArray[3] == myArray[0] {
print("myArray[3] == myArray[0]")
}

How to get all enum values as an array

For Swift 4.2 (Xcode 10) and later

There's a CaseIterable protocol:

enum EstimateItemStatus: String, CaseIterable {
case pending = "Pending"
case onHold = "OnHold"
case done = "Done"

init?(id : Int) {
switch id {
case 1: self = .pending
case 2: self = .onHold
case 3: self = .done
default: return nil
}
}
}

for value in EstimateItemStatus.allCases {
print(value)
}

For Swift < 4.2

No, you can't query an enum for what values it contains. See this article. You have to define an array that list all the values you have. Also check out Frank Valbuena's solution in "How to get all enum values as an array".

enum EstimateItemStatus: String {
case Pending = "Pending"
case OnHold = "OnHold"
case Done = "Done"

static let allValues = [Pending, OnHold, Done]

init?(id : Int) {
switch id {
case 1:
self = .Pending
case 2:
self = .OnHold
case 3:
self = .Done
default:
return nil
}
}
}

for value in EstimateItemStatus.allValues {
print(value)
}

Multiple enum types list all cases

Here is a demo of possible solution. Prepared with Xcode 12.1 / iOS 14.1

demo

enum Fish: String, CaseIterable {
case goldfish
case blueTang = "blue_tang"
case shark
}

func view<T: CaseIterable & Hashable>(for type: T.Type) -> some View where T.AllCases: RandomAccessCollection {
VStack(alignment: .leading) {
Text(String(describing: type)).bold()
ForEach(type.allCases, id: \.self) { item in
Text(String(describing: item))
}
}
}

struct FishDemoView: View {
var body: some View {
view(for: Fish.self)
}
}

How to enumerate an enum with String type?

Swift 4.2+

Starting with Swift 4.2 (with Xcode 10), just add protocol conformance to CaseIterable to benefit from allCases. To add this protocol conformance, you simply need to write somewhere:

extension Suit: CaseIterable {}

If the enum is your own, you may specify the conformance directly in the declaration:

enum Suit: String, CaseIterable { case spades = "♠"; case hearts = "♥"; case diamonds = "♦"; case clubs = "♣" }

Then the following code will print all possible values:

Suit.allCases.forEach {
print($0.rawValue)
}


Compatibility with earlier Swift versions (3.x and 4.x)

If you need to support Swift 3.x or 4.0, you may mimic the Swift 4.2 implementation by adding the following code:

#if !swift(>=4.2)
public protocol CaseIterable {
associatedtype AllCases: Collection where AllCases.Element == Self
static var allCases: AllCases { get }
}
extension CaseIterable where Self: Hashable {
static var allCases: [Self] {
return [Self](AnySequence { () -> AnyIterator<Self> in
var raw = 0
var first: Self?
return AnyIterator {
let current = withUnsafeBytes(of: &raw) { $0.load(as: Self.self) }
if raw == 0 {
first = current
} else if current == first {
return nil
}
raw += 1
return current
}
})
}
}
#endif

Passing various enum case as function param in Swift

The linked question is actually quite close - you just have to change the parameter type to just T, instead of T.Type:

func printCase<T : RawRepresentable>(_ e: T) where T.RawValue == String {
print(e.rawValue)
}

Since you are accepting an instance of the enum, not the enum type itself.

Of course, you don't have to restrict this to enums where T.RawValue == String, since print can print Anything.

How to print associated values in Swift enumerations?

The problem is that you added an explicit raw type to your Barcode enum—String. Declaring that it conforms to Printable is all you need:

enum Barcode: Printable {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
var description: String {
// ...
}
}

The compiler's complaint is that you didn't specify raw values with your non-integer raw value type, but you can't do that with associated values anyway. Raw string values, without associated types, could look like this:

enum CheckerColor: String, Printable {
case Red = "Red"
case Black = "Black"
var description: String {
return rawValue
}
}

How do I get the count of a Swift enum?

As of Swift 4.2 (Xcode 10) you can declare
conformance to the CaseIterable protocol, this works for all
enumerations without associated values:

enum Stuff: CaseIterable {
case first
case second
case third
case forth
}

The number of cases is now simply obtained with

print(Stuff.allCases.count) // 4

For more information, see

  • SE-0194 Derived Collection of Enum Cases

Enum: Count and list all cases (from outside!)

I tried in 1 file:

enum TestEnum: CaseIterable {
case test1
case test2
}

in another file of another class I wrote:

let count = TestEnum.allCases.count

And it works, but I noticed that when I was typing "allCases" wasn't shown

Sample Image

I manually needed to write it



Related Topics



Leave a reply



Submit