enum have a property named 'hashValue' which is its index inside the enum.
Now my question is, is it possible to access its value by using a number? Ex: let variable:AnEnum = 0
enum have a property named 'hashValue' which is its index inside the enum.
Now my question is, is it possible to access its value by using a number? Ex: let variable:AnEnum = 0
If you want to map enum values to integers, you should do so directly with raw values. For example (from the Swift Programming Language: Enumerations):
enum Planet: Int {
case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
let possiblePlanet = Planet(rawValue: 7)
I don't believe there's any documentation promising that an enum's hashValue is anything in particular (if you have a link, I've be very interested). In the absence of that, you should be explicit in your assignment of raw values.
enum Opponent: String {
case Player
case Computer
static func fromHashValue(hashValue: Int) -> Opponent {
if hashValue == 0 {
return .Player
} else {
return .Computer
}
}
}
Explanation:
Since there is no way to get back an enum value from its hashValue, you have to do it manually. It's not pretty, but it works. You essentially create a function that allows you to pass in the index of the value you want and manually return that enum value back to the caller. This could get nasty with an enum with tons of cases, but it works like a charm for me.
Swift 4, iOS 12:
Simply make your enum with explicitly setting raw type (like Int
in below example):
enum OrderStatus: Int {
case noOrder
case orderInProgress
case orderCompleted
case orderCancelled
}
Usage:
var orderStatus: OrderStatus = .noOrder // default value
print(orderStatus.rawValue) // it will print 0
orderStatus = .orderCompleted
print(orderStatus.rawValue) // it will print 2
This answer uses switch instead of if/else clauses. And returns optional as your not garantueed that the hash provided will match.
enum CellType:String{
case primary,secondary,tierary
/**
* NOTE: Since there is no way to get back an enum value from its hashValue, you have to do it manually.
* EXAMPLE: CellType.fromHashValue(hashValue: 1)?.rawValue//primary
*/
static func fromHashValue(hashValue: Int) -> CellType? {
switch hashValue {
case 0:
return .primary
case 1:
return .secondary
case 2:
return .tierary
default:
return nil
}
}
}
Your requirement is to have this line of code working, where 0
is the hashValue
of the enum variable (note that starting with Xcode 10, 0
is never a valid hashValue...):
let variable:AnEnum = 0
This is simply done by making your enum ExpressibleByIntegerLiteral
and CaseIterable
:
extension AnEnum: CaseIterable, ExpressibleByIntegerLiteral {
typealias IntegerLiteralType = Int
public init(integerLiteral value: IntegerLiteralType) {
self = AnEnum.allCases.first { $0.hashValue == value }!
}
}
The CaseIterable
protocol is natively available with Swift 4.2, and you can implement it yourself for older swift versions (Swift 3.x, 4.x) using the code from https://stackoverflow.com/a/49588446/1033581.
Actually, with Swift 4.2, the hashValue
is not the index inside the enum
anymore.
Edit: Just found a safer way to achieve that. You can use the CaseIterable
(Swift 4.2) and pick the desired case in the allCases
collection.
enum Foo: CaseIterable {
case bar
case baz
init?(withIndex index: Int) {
guard Foo.allCases.indices ~= index else { return nil }
self = Foo.allCases[index]
}
}
Foo(withIndex: 0) // bar
Foo(withIndex: 1) // baz
Foo(withIndex: 2) // nil
Note: I'm leaving this little trick here, because playing with unsafe pointer is fun, but please, do not use this method to create a case with an index. It relies on Swift memory representation which might change without notice, and is really unsafe because using a wrong index produce a runtime error.
That being said, in Swift, a case is represented using an Int
in raw memory. So you can use this to build a case using unsafe pointers.
enum Foo {
case bar
case baz
init(withIndex index: UInt8) {
var temp: Foo = .bar
withUnsafeMutablePointer(to: &temp) { pointer in
let ptr = UnsafeMutableRawPointer(pointer).bindMemory(to: UInt8.self, capacity: 1)
ptr.pointee = index
}
self = temp
}
}
Foo(withIndex: 0) // bar
Foo(withIndex: 1) // baz
Foo(withIndex: 2) // runtime error !