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
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 Any
thing.
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
I manually needed to write it
Related Topics
Bool.Hashvalue Valid to Convert to Int
Compiling for iOS 10.3, But Module 'swiftuicharts' Has a Minimum Deployment Target of iOS 13.0
Why Cannot Read The Receipt Data for On-Device Validation
Extension for Array Where Element Is Optional
Adding Drop Shadow to Table View Cell
Could Not Find an Overload for "Init" That Accepts The Supplied Arguments (Swift)
How to Force Sktextureatlas Created from a Dictionary to Not Modify Textures Size
Literal Numbers in Floatingpoint Protocol
Onreceive String.Publisher Lead to Infinite Loop
Adding Constraints Programmatically in UIview with UItextview
Swift: Simple Dispatchqueue Does Not Run & Notify Correctly
Crashlytics Doesn't Work with Xcode 10 Beta
Support Arkit in Lower End Devices
Way to Check If Up or Down Button Is Pressed with Nsstepper