Is it possible to change an enum from inside an enum method? - swift

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 !.

Related

Error comparing Integers: Binary operator '<=' cannot be applied to operands of type 'Int?' and 'Int'

I have the following implementation:
class MyClass{
static let sharedInstance = MyClass()
public var someNumber:Int = 10
private func doSomething(){
if self?.someNumber <= 0 {
}
}
}
But when I'm trying to compare if is less or equal to zero I get this error:
If I try the solution on this post I get this error:
Cannot force unwrap value of non-optional type 'Int'
Any of you knows how can I fix this error or if there is any work around this?
If you need self?, it looks like you are not including all of the code. Perhaps the code is really in a closure with weak self?
It looks as if self is nil when you call this. If so, you need to do something else, like
if (self?.someNumber ?? 0) <= 0 {
}
This says, that if self is nil, then use 0 instead of someNumber. If you always want to use 10, you could use that after the ??.
Or you could if let check the value and do something completely different in the else.
You don't have to unwrap. someNumber is not an optional. Just do:
class MyClass{
static let sharedInstance = MyClass()
public var someNumber:Int = 10
private func doSomething() {
if self.someNumber <= 0 {
}
}
}
I think we're missing some code. How can self be nullable? This only happens to me when I have some kind of [weak self] block. In that case, I recast it first:
guard let strongSelf = self else {
return // Probably this ViewController or object got released after the long running operation
}
if strongSelf.someNumber <= 0 {
// Do stuff
}

Using a Type Variable in a Generic

I have this question except for Swift. How do I use a Type variable in a generic?
I tried this:
func intType() -> Int.Type {
return Int.self
}
func test() {
var t = self.intType()
var arr = Array<t>() // Error: "'t' is not a type". Uh... yeah, it is.
}
This didn't work either:
var arr = Array<t.Type>() // Error: "'t' is not a type"
var arr = Array<t.self>() // Swift doesn't seem to even understand this syntax at all.
Is there a way to do this? I get the feeling that Swift just doesn't support it and is giving me somewhat ambiguous error messages.
Edit: Here's a more complex example where the problem can't be circumvented using a generic function header. Of course it doesn't make sense, but I have a sensible use for this kind of functionality somewhere in my code and would rather post a clean example instead of my actual code:
func someTypes() -> [Any.Type] {
var ret = [Any.Type]()
for (var i = 0; i<rand()%10; i++) {
if (rand()%2 == 0){ ret.append(Int.self) }
else {ret.append(String.self) }
}
return ret
}
func test() {
var ts = self.someTypes()
for t in ts {
var arr = Array<t>()
}
}
Swift's static typing means the type of a variable must be known at compile time.
In the context of a generic function func foo<T>() { ... }, T looks like a variable, but its type is actually known at compile time based on where the function is called from. The behavior of Array<T>() depends on T, but this information is known at compile time.
When using protocols, Swift employs dynamic dispatch, so you can write Array<MyProtocol>(), and the array simply stores references to things which implement MyProtocol — so when you get something out of the array, you have access to all functions/variables/typealiases required by MyProtocol.
But if t is actually a variable of kind Any.Type, Array<t>() is meaningless since its type is actually not known at compile time. (Since Array is a generic struct, the compiler needs know which type to use as the generic parameter, but this is not possible.)
I would recommend watching some videos from WWDC this year:
Protocol-Oriented Programming in Swift
Building Better Apps with Value Types in Swift
I found this slide particularly helpful for understanding protocols and dynamic dispatch:
There is a way and it's called generics. You could do something like that.
class func foo() {
test(Int.self)
}
class func test<T>(t: T.Type) {
var arr = Array<T>()
}
You will need to hint the compiler at the type you want to specialize the function with, one way or another. Another way is with return param (discarded in that case):
class func foo() {
let _:Int = test()
}
class func test<T>() -> T {
var arr = Array<T>()
}
And using generics on a class (or struct) you don't need the extra param:
class Whatever<T> {
var array = [T]() // another way to init the array.
}
let we = Whatever<Int>()
jtbandes' answer - that you can't use your current approach because Swift is statically typed - is correct.
However, if you're willing to create a whitelist of allowable types in your array, for example in an enum, you can dynamically initialize different types at runtime.
First, create an enum of allowable types:
enum Types {
case Int
case String
}
Create an Example class. Implement your someTypes() function to use these enum values. (You could easily transform a JSON array of strings into an array of this enum.)
class Example {
func someTypes() -> [Types] {
var ret = [Types]()
for _ in 1...rand()%10 {
if (rand()%2 == 0){ ret.append(.Int) }
else {ret.append(.String) }
}
return ret
}
Now implement your test function, using switch to scope arr for each allowable type:
func test() {
let types = self.someTypes()
for type in types {
switch type {
case .Int:
var arr = [Int]()
arr += [4]
case .String:
var arr = [String]()
arr += ["hi"]
}
}
}
}
As you may know, you could alternatively declare arr as [Any] to mix types (the "heterogenous" case in jtbandes' answer):
var arr = [Any]()
for type in types {
switch type {
case .Int:
arr += [4]
case .String:
arr += ["hi"]
}
}
print(arr)
I would break it down with the things you already learned from the first answer. I took the liberty to refactor some code. Here it is:
func someTypes<T>(t: T.Type) -> [Any.Type] {
var ret = [Any.Type]()
for _ in 0..<rand()%10 {
if (rand()%2 == 0){ ret.append(T.self) }
else {
ret.append(String.self)
}
}
return ret
}
func makeArray<T>(t: T) -> [T] {
return [T]()
}
func test() {
let ts = someTypes(Int.self)
for t in ts {
print(t)
}
}
This is somewhat working but I believe the way of doing this is very unorthodox. Could you use reflection (mirroring) instead?
Its possible so long as you can provide "a hint" to the compiler about the type of... T. So in the example below one must use : String?.
func cast<T>(_ value: Any) -> T? {
return value as? T
}
let inputValue: Any = "this is a test"
let casted: String? = cast(inputValue)
print(casted) // Optional("this is a test")
print(type(of: casted)) // Optional<String>
Why Swift doesn't just allow us to let casted = cast<String>(inputValue) I'll never know.
One annoying scenerio is when your func has no return value. Then its not always straightford to provide the necessary "hint". Lets look at this example...
func asyncCast<T>(_ value: Any, completion: (T?) -> Void) {
completion(value as? T)
}
The following client code DOES NOT COMPILE. It gives a "Generic parameter 'T' could not be inferred" error.
let inputValue: Any = "this is a test"
asyncCast(inputValue) { casted in
print(casted)
print(type(of: casted))
}
But you can solve this by providing a "hint" to compiler as follows:
asyncCast(inputValue) { (casted: String?) in
print(casted) // Optional("this is a test")
print(type(of: casted)) // Optional<String>
}

Mode flipping of Enum var

What’s the best way to flip between Enum state?
enum EVEN_ODD { case Even, Odd }
var __mode_bit = EVEN_ODD.Even;
for _ in 1...5 {
__mode_bit = (__mode_bit == .Even) ? .Odd : .Even
}
Could the __mode_bit?: be simplified?
Take a look at the Apple documentation on Booleans, they give an example of a Boolean typed enum: https://developer.apple.com/swift/blog/?id=8
Since you can create an enum from raw, you could toggle the value by:
let true = MyBool(rawValue: false)
Simon
My preference would be to make the enum conform to _Incrementable (which, for some reason, is underscored even though it seems like a reasonable non-internal protocol to me), and make it wrap around.
enum EvenOdd {
case Even, Odd
}
extension EvenOdd: _Incrementable {
func successor() -> EvenOdd {
return self == .Even ? .Odd : .Even
}
}
EvenOdd.Odd.successor() // == .Even
This also gives you a pre/post increment operator for free:
var bit = EvenOdd.Odd
++bit // bit now Even
++bit // bit now Odd
++bit // bit now Even etc
Enums can have the ! operator implemented for them.
enum Parity { case Even, Odd }
prefix func !(a: Parity) -> Parity {
return a == .Even ? .Odd : .Even
}
Now I can stuff like
var parity_mode = Parity.Even
parity_mode = !parity_mode // .Odd
Based on #Simon Gladman answer with reference to Boolean

how to increment a swift int enumeration

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

iOS Swift Error: 'T' is not convertible to 'MirrorDisposition'

I am attempting to create an extension method for the Array type to allow for removing an item from an array
extension Array {
func remove(item: AnyObject) {
for var i = self.count - 1; i >= 0; i-- {
if self[i] == item {
self.removeAtIndex(i)
}
}
}
}
On the test condition if self[i] == item, I get the following error: 'T' is not convertible to 'MirrorDisposition'
I've tried many different things, which include:
Using generics: remove<T>(item: T)
Using the === operator, which just gives the error 'T' does not conform to protocol 'AnyObject'
I'm new to Swift, so this is where my knowledge runs out. Any suggestions would be greatly appreciated.
You are getting an error because the compiler can't guarantee that the element stored in your array can be compared with ==. You have to ensure that it the contained type is Equatable. However, there is no way to add a method to a generic class that is more restrictive than the class itself. It is better to implement it as a function:
func removeItem<T: Equatable>(item: T, var fromArray array: [T]) -> [T] {
for i in reverse(0 ..< array.count) {
if array[i] == item {
array.removeAtIndex(i)
}
}
return array
}
Or you could add it as a more generic extension:
extension Array {
mutating func removeObjectsPassingTest(test: (object: T) -> Bool) {
for var i : Int = self.count - 1; i >= 0; --i {
if test(object: self[i]) {
self.removeAtIndex(i)
}
}
}
}
Then you can do this:
var list: [Int] = [1,2,3,2,1]
list.removeObjectsPassingTest({$0 == 2})
The way I would write this function is like this:
mutating func remove<U where U : Equatable>(item: U) {
for var i = self.count - 1; i >= 0; i-- {
if self[i] as U == item {
self.removeAtIndex(i)
}
}
}
Be sure to decorate your function with mutating.
I would use a different type parameter U since you can't really change Array's type parameter to be Equatable. Then I would try to cast the items to U to do the comparison.
Of course, this will fail if you try to call this function with an Array that is instantiated with a non-equatable type.
This is not a solution but if you are trying to remove an item from an array, this is how I do it:
var numbers = [1, 2, 3, 4, 5]
if let possibleIndex = find(numbers, 1) {
numbers.removeAtIndex(possibleIndex)
}
The error message is confusing. The problem why it does not work is because Swift compiler can not find == operator for Array's element type T. For this to work T would need to conform to Equatable protocol.
I don't know what is MirrorDispsition, but I think the problem is that you can't always equate two objects in Array, because they are not guaranteed to be equatable.
Edit: Look at tng's solution. It will only work with equatable items, though.