iTranslated by AI
The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🕊
[Swift] Why You Must Manually Define allCases for Enums with Associated Values When Conforming to CaseIterable
What this article covers
- When conforming to the
CaseIterableprotocol for enums with associated values, you must manually defineallCases.
Concrete Examples
Example 1: Standard usage of CaseIterable
enum Color: CaseIterable {
case red, green, blue
}
Color.allCases.forEach {
print($0)
}
// Output
//
// red
// green
// blue
Example 2: Using CaseIterable with enums with associated values
For an enum with associated values like the one below, adding CaseIterable will trigger the compiler error: Type 'Trade' does not conform to protocol 'CaseIterable'.
enum Trade: CaseIterable { // Type 'Trade' does not conform to protocol 'CaseIterable'
case buy(stock: String, amount: Int)
case sell(stock: String, amount: Int)
}
Therefore, you must define allCases yourself and provide specific values as follows:
enum Trade: CaseIterable {
// Must define allCases manually
static var allCases: [Trade] {
return [
.buy(stock: "", amount: 0),
.sell(stock: "", amount: 0)
]
}
case buy(stock: String, amount: Int)
case sell(stock: String, amount: Int)
}
Trade.allCases.forEach {
print($0)
}
// Output
//
// buy(stock: "", amount: 0)
// sell(stock: "", amount: 0)
Example 3: When the "associated value" is itself an enum that conforms to CaseIterable
So, what happens if the associated value of an enum is another enum that conforms to CaseIterable? You might hope the compiler would be smart enough to handle this automatically.
After testing this, it turns out the compiler still complains, and you are required to define allCases yourself (sadly).
Here is how you would have to write it out manually:
enum FinancialProduct: CaseIterable {
case stock
case gold
case crypto
}
enum Trade: CaseIterable {
static var allCases: [Trade] {
return [
FinancialProduct.allCases.map { .buy(financialProduct: $0) },
FinancialProduct.allCases.map { .sell(financialProduct: $0) },
].flatMap { $0 }
}
case buy(financialProduct: FinancialProduct)
case sell(financialProduct: FinancialProduct)
}
Trade.allCases.forEach { trade -> () in
switch trade {
case let .buy(financialProduct):
print("buy: \(financialProduct)")
case let .sell(financialProduct):
print("sell: \(financialProduct)")
}
}
// Output
//
// buy: stock
// buy: gold
// buy: crypto
// sell: stock
// sell: gold
// sell: crypto
Conclusion
- Be careful when using
CaseIterablewithenumtypes that have associated values.
Discussion