I have a swift enumeration
enum MainState : Int {
case NotStarted
case Init
case AskWhatToText
case RecordWhatToText
}
var state = MainState.NotStarted
and would like to do something like
state++
but get an error. suggestions?
This is not C, where enums are integers. In swift an enum is a proper type in it's own right and you cannot perform math operations on it.
However, you can grab the raw value which is an integer, and do math on that. Then create a new enum:
var newState = MainState(rawValue: state.rawValue + 1)
Note that "newState" is an optional. You'll get null if rawValue + 1 doesn't exist in the enum.
What do you want to happen when you increment an enum? What should happen when it's on the RecordWhatToText state and you increment it again, or on the NotStarted state and you decrement it? These are questions that have more to do with your enum and less with the design of enums in general. (After all, the designer of one enum might want it to loop around, another might want it to stay at the max value, and another might want to make incrementing past the max be an error.) I'd presume that's at least part of why custom enums don't come with increment operators out of the box.
There's no saying you can't make your own operators that fit the design of how you want your enum to be used, though. This example makes attempting to increment past the maximum a no-op:
postfix func ++(inout state: MainState) {
if let newValue = MainState(rawValue: state.rawValue + 1) {
state = newValue
} else {
// leave state alone
}
}
Note that you'll also need to make a prefix func ++ if you also want pre-increment, and you might consider making decrement operators, too.
extension CaseIterable where Self: Equatable {
static postfix func ++(c: inout Self) {
let all = Self.allCases
let idx = all.firstIndex(of: c)!
let next = all.index(after: idx)
c = all[next == all.endIndex ? all.startIndex : next]
}
static postfix func --(c: inout Self) {
let all = Self.allCases
var idx = all.firstIndex(of: c)!
if idx == all.startIndex {
let lastIndex = all.index(all.endIndex, offsetBy: -1)
c = all[lastIndex]
} else {
all.formIndex(&idx, offsetBy: -1)
c = all[idx]
}
}
}
Usage:
enum MainState: Int, CaseIterable {
case notStarted
case `init`
case askWhatToText
case recordWhatToText
}
var state = MainState.notStarted
state++
print(state) // init
state++
print(state) // askWhatToText
state--
print(state) // init
Related
Is there a way to convert an integer to an enum based on its value range? For the sake of elegance, I prefer to implement it into an enum or auxiliary type rather than as a separate function. Ideally, it would be great if I could perform the conversion using a cast like so:
let readPosition = Position(controller.readVal())
or
let readPosition = (Position) controller.readVal()
Below is my feeble attempt at it:
// Should be sealed, yet extensible, c# has sealed, but not Swift
public enum Position: Int {
case Both = 0, Bottom = 1, Top = 2
}
// Position should not be changed to preserve compatibility.
// Different converters will be implemented by different apps
// overtime.
extension Position {
static func convert(val: Int64?) -> Position {
switch val {
case .some(1), .some(..<8):
return Position.Top
case .some(2), .some(8...):
return Position.Bottom
default:
return Position.Both
}
}
}
You already have all you need, you can now define an initializer:
extension Position {
init(_ val: Int64) {
self = Self.convert(val)
}
}
Then you can use your requested:
let readPosition = Position(controller.readVal())
Can I create a generator in Swift?
With iterator, I need store intermediate results, for example:
struct Countdown: IteratorProtocol, Sequence {
private var value = 0
init(start: Int) {
self.value = start
}
mutating func next() -> Int? {
let nextNumber = value - 1
if nextNumber < 0 {
return nil
}
value -= 1
return nextNumber
}
}
for i in Countdown(start: 3) {
print(i)
} // print 1 2 3
In this example, I need store the value.
In my situation, I want to use generator instead of iterator, because I don't want store the intermediate results of my sequence in each next.
Understanding how generators work (and why they are less important in swift) is at first difficult coming from Python.
Up to Swift v2.1 there was a protocol called GeneratorType. This was renamed to IteratorProtocol in Swift v3.0+. You can conform to this protocol to make your own objects that do just-in-time computations similar to what can be done in Python.
More information can be found in the Apple Documentation: IteratorProtocol
A simple example from IteratorProtocol page:
struct CountdownIterator: IteratorProtocol {
let countdown: Countdown
var times = 0
init(_ countdown: Countdown) {
self.countdown = countdown
}
mutating func next() -> Int? {
let nextNumber = countdown.start - times
guard nextNumber > 0
else { return nil }
times += 1
return nextNumber
}
}
let threeTwoOne = Countdown(start: 3)
for count in threeTwoOne {
print("\(count)...")
}
// Prints "3..."
// Prints "2..."
// Prints "1..."
However, you need to think about why you are using a generator:
Swift automatically does something "called copy on write." This means that many of the cases that use a Python generator to avoid the large copying cost of collections of objects (arrays, lists, dictionaries, etc) are unnecessary in Swift. You get this for free by using one of the types that use copy on write.
Which value types in Swift supports copy-on-write?
It is also possible to use a wrapper to force almost any object to be copy on write, even if it is not part of a collection:
How can I make a container with copy-on-write semantics?
The optimizations in swift usually mean that you do not not have to write generators. If you really do need to (usually because of data heavy, scientific calculations) it is possible as above.
Based on the code you provided and the little bit knowledge of generators that I do have, you can do something like
struct Countdown {
private var _start = 0
private var _value = 0
init(value: Int) {
_value = value
}
mutating func getNext() -> Int? {
let current = _start
_start += 1
if current <= _value {
return current
} else {
return nil
}
}
}
and then wherever you want to use it, you can do something like
var counter = Countdown(value: 5)
while let value = counter.getNext() {
print(value)
}
Walter provides a lot of good information, and generally you shouldn't be doing this in Swift, but even if you wanted an Iterator, the right way to do it is with composition, not by building your own. Swift has a lot of existing sequences that can be composed to create what you want without maintaining your own state. So in your example, you'd differ to a range's iterator:
struct Countdown: Sequence {
private var value = 0
init(start: Int) {
self.value = start
}
func makeIterator() -> AnyIterator<Int> {
return AnyIterator((0..<value).reversed().makeIterator())
}
}
for i in Countdown(start: 3) {
print(i)
} // print 1 2 3
Something has to keep the state; that's the nature of these kinds of functions (even in a world with coroutines). It's fine not to maintain it directly; just delegate to a more primitive type. Swift has a couple of dozen built-in Iterators you can use to build most things you likely need, and any iterator can be lifted to an AnyIterator to hide the implementation details. If you have something custom enough that it really requires a next(), then yes, storing the state is your problem. Something has to do it. But I've found this all to be extremely rare, and often suggests over-design when it comes up.
I have a solution similar to above, but with a slightly more "yield-y" feeling to it.
struct Countdown
{
static func generator(withStart: Int) -> () -> Int?
{
var start = withStart + 1
return {
start = start - 1
return start > 0 ? start : nil
}
}
}
let countdown = Countdown.generator(withStart: 5)
while let i = countdown()
{
print ("\(i)")
}
Consider this code:
enum Type {
case Foo(Int)
case Bar(Int)
var isBar: Bool {
if case .Bar = self {
return true
} else {
return false
}
}
}
That's gross. I would like to write something like this instead:
enum Type {
case Foo(Int)
case Bar(Int)
var isBar: Bool {
return case .Bar = self
}
}
But such a construct does not seem to exist in Swift, or I cannot find it.
Since there's data associated with each case, I don't think it's possible to implement the ~= operator (or any other helper) in a way that's equivalent to the above expression. And in any case, if case statements exist for free for all enums, and don't need to be manually implemented.
Thus my question: is there any more concise/declarative/clean/idiomatic way to implement isBar than what I have above? Or, more directly, is there any way to express if case statements as Swift expressions?
UPDATE 2:
Another workaround... Create a var that returns an Int ONLY based on the case, then use a static (or instance, I thought static looked cleaner) method to test equivalence of just the case. It won't clash with Equatable, you don't have to overload an operator (unless you want to replace the static method with one), and you also wouldn't have to create separate var isFoo, var isBar, etc.
I know you used this example to ask a more generic question (how can I use 'if case' as an expression?) but if that's not possible, this may be a valid workaround. I apologize if this treats "the symptoms" not "the problem"
enum Something{
case Foo(Int)
case Bar(Int)
static func sameCase(a: Something, b: Something) -> Bool {
return a.caseValue == b.caseValue
}
var caseValue: Int {
switch self {
case .Foo(_):
return 0
case .Bar(_):
return 1
}
}
//if necessary
var isBar: Bool {
return Something.sameCase(self, b: Something.Bar(0))
}
}
Something.sameCase(.Bar(0), b: .Foo(0)) // false
Something.sameCase(.Bar(1), b: .Foo(2)) // false
Something.sameCase(.Foo(0), b: .Foo(0)) // true
Something.sameCase(.Bar(1), b: .Bar(2)) // true
Something.Bar(0).isBar // true
Something.Bar(5).isBar // true
Something.Foo(5).isBar // false
UPDATE 1:
Ok, so this seems to work. If you overload the == operator to ignore values and return true only when both enums are the same case, you can pass any value in your isFoo method and still determine the type.
I'm assuming you will need to customize this function to accommodate the the associated values, but it seems like a step in the right direction
enum Something {
case Foo(Int)
case Bar(Int)
var isFoo: Bool {
return self == .Foo(0) // number doesn't matter here... see below
}
}
func ==(a: Something, b: Something) -> Bool {
switch (a,b) {
case (.Bar(_), .Bar(_)):
return true
case (.Foo(_), .Foo(_)):
return true
default:
return false
}
}
let oneFoo = Something.Foo(1)
let twoFoo = Something.Foo(2)
let oneBar = Something.Bar(1)
let twoBar = Something.Bar(2)
oneFoo == twoFoo // true
oneFoo == oneFoo // true
oneFoo == oneBar // false
oneFoo == twoBar // false
OLD:
You can use self and the case name to directly check which case it is, you don't have to use the case keyword. Hopefully this will work for your situation:
enum Something{
case Foo(Int)
case Bar(Int)
var isFoo: Bool {
switch self {
case Foo:
return true
case Bar:
return false
}
}
}
So, there is a neater way, but requires a 3rd-party package: CasePaths
The idea is they work similarly to KeyPaths, and they come with a / operator to trigger it. There is also a ~= operator to check if a CasePath matches an instance.
So, you can achieve something like your original example like so:
import CasePaths
enum Type {
case Foo(Int)
case Bar(Int)
var isBar: Bool {
/Self.Bar ~= self
}
}
You can also get the value:
extension Type {
/// Returns the `Int` if this is a `Bar`, otherwise `nil`.
var barValue: Int? {
(/Self.Bar).extract(from: self)
}
}
You can do several other useful things with CasePaths as well, such as extracting the Foo values in an array of Type values:
let values: [Type] = [.Foo(1), .Bar(2), .Foo(3), .Foo(4), .Bar(5)]
let foos = values.compactMap(/Type.Foo) // [1, 3, 4]
let bars = values.compactMap(/Type.Bar) // [2, 5]
I'm sure there is somewhat of a performance cost, but it may not be an issue in your context.
I have a similar wondering, and I kept searching for some work arounds about this, and landed on this page. I came up with code like this to compromise.
fileprivate enum TypePrimitive {
case foo
case bar
}
enum Type {
case foo(Int)
case bar(Int)
fileprivate var primitiveType: TypePrimitive {
switch self {
case .foo(_): return .foo
case .bar(_): return .bar
}
}
var isFoo: Bool { self.primitiveType == .foo }
var isBar: Bool { self.primitiveType == .bar }
}
I hope Apple will provide better solution by adding some features in Swift language.
Are you looking for the ? operator ?
documentation is here under the Ternary Conditional Operator title.
I have an enum in Swift:
enum Orientation: Int
{
case Rot_0 = 0, Rot_90, Rot_180, Rot_270
and a non-static method within my enum designed to shift the orientation clockwise or counterclockwise:
func rotate(clockwise: Bool)
{
var nextRawValue = self.rawValue + (clockwise ? 1 : -1)
if nextRawValue < Orientation.Rot_0.rawValue
{
nextRawValue = Orientation.Rot_270.rawValue
}
else if nextRawValue > Orientation.Rot_270.rawValue
{
nextRawValue = Orientation.Rot_0.rawValue
}
self = Orientation(rawValue: nextRawValue)
}
The the compiler is telling me that you cannot assign to self in a method. I'm having trouble understanding why this isn't possible.
The only thing I can think of is having a static method rotate(orientation: Orientation, clockwise: Bool), but in this case, the return value must be explicitly assigned back to the enum variable, and that just feels like bad coding to me. It seems like it would be much more useful to say myOrientation.rotate() and have the value changed implicitly.
Is there an elegant solution to this problem?
Thanks guys!
When you're going to modify a value type (i.e., struct or enum) in a method, you need to mark it as mutating. This will make the method usable by mutable instances (declared with var ...) but not immutable instances (let ...):
mutating func rotate(clockwise: Bool)
{
var nextRawValue = self.rawValue + (clockwise ? 1 : -1)
if nextRawValue < Orientation.Rot_0.rawValue
{
nextRawValue = Orientation.Rot_270.rawValue
}
else if nextRawValue > Orientation.Rot_270.rawValue
{
nextRawValue = Orientation.Rot_0.rawValue
}
self = Orientation(rawValue: nextRawValue)!
}
Note that fixing the mutating error reveals another -- Orientation(rawValue: nextRawValue) returns an optional, so you need to unwrap it before you can assign to self. If you've implemented the prior logic correctly, you should be safe in using the force unwrapping operator !.
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
Swift 4.2 🔸(Based on previous answer by #Stephen paul)
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 !