Xcode 9 and Xcode 10 giving different results, even with same swift version
The solution for this is below for Xcode 10 and Swift 4.2 and above.
Step 1: Create Protocol EnumIterable.
protocol EnumIterable: RawRepresentable, CaseIterable {
var indexValue: Int { get }
}
extension EnumIterable where Self.RawValue: Equatable {
var indexValue: Int {
var index = -1
let cases = Self.allCases as? [Self] ?? []
for (caseIndex, caseItem) in cases.enumerated() {
if caseItem.rawValue == self.rawValue {
index = caseIndex
break
}
}
return index
}
}
Step 2: Extend EnumIterator Protocol to your enums.
enum Colors: String, EnumIterable {
case red = "Red"
case yellow = "Yellow"
case blue = "Blue"
case green = "Green"
}
Step 3: Use indexValue property like using hashValue.
Colors.red.indexValue
Colors.yellow.indexValue
Colors.blue.indexValue
Colors.green.indexValue
Sample Print statement and Output
print("Index Value: \(Colors.red.indexValue), Raw Value: \(Colors.red.rawValue), Hash Value: \(Colors.red.hashValue)")
Output: "Index Value: 0, Raw Value: Red, Hash Value: 1593214705812839748"
print("Index Value: \(Colors.yellow.indexValue), Raw Value: \(Colors.yellow.rawValue), Hash Value: \(Colors.yellow.hashValue)")
Output: "Index Value: 1, Raw Value: Yellow, Hash Value: -6836447220368660818"
print("Index Value: \(Colors.blue.indexValue), Raw Value: \(Colors.blue.rawValue), Hash Value: \(Colors.blue.hashValue)")
Output: "Index Value: 2, Raw Value: Blue, Hash Value: -8548080225654293616"
print("Index Value: \(Colors.green.indexValue), Raw Value: \(Colors.green.rawValue), Hash Value: \(Colors.green.hashValue)")
Output: "Index Value: 3, Raw Value: Green, Hash Value: 6055121617320138804"
That is an undocumented way to get a sequence of all enumeration values, and worked only by chance with earlier Swift versions. It relies on the hash values of the enumeration values being consecutive integers, starting at zero.
That definitely does not work anymore with Swift 4.2 (even if running in Swift 4 compatibility mode) because hash values are now always randomized, see SE-0206 Hashable Enhancements:
To make hash values less predictable, the standard hash function uses a per-execution random seed by default.
You can verify that with
print(NumberEnum.one.hashValue)
print(NumberEnum.two.hashValue)
which does not print 0
and 1
with Xcode 10, but some
other values which also vary with each program run.
For a proper Swift 4.2/Xcode 10 solution, see How to enumerate an enum with String type?:
extension NumberEnum: CaseIterable { }
print(Array(NumberEnum.allCases).count) // 4