How to pass global variables through switch/case - swift

I realise this has been asked before, but the answer here (to declare the variable outside the block) doesn't seem to work.
link description
var filter: String
func Usage() {
print("Usage: <filter> <input> [output]")
print("System filter paths do not need to be specified.")
return
}
let arguments = ["qwe", "value", "qwe", "asd"]
print(arguments.count)
switch arguments.count {
case 1:
Usage()
case 2:
Usage()
case 3:
filter = arguments[1]
default:
filter = arguments[1]
print (filter)
}
print (filter)
I get "value" in Xcode's playground for the first print, but the second gives "\n" or "value not initialized".
What am I doing wrong?

Your code won´t compile first of all, you do get the error error: variable 'filter' used before being initialized
So declare filter as follow:
var filter = String() or var filter = ""
Secondly since you´re not adding all of your code I tried the following:
var filter = String()
let x = 0
switch x {
case 1:
print("1")
default:
filter = "value"
print(filter)
}
print(filter)
This prints out:
value
value
If you need further help update your question with more information.
Update:
Just tried your updated code:
var filter = String()
let arguments = ["qwe", "value", "qwe", "asd"]
print(arguments.count)
switch arguments.count {
case 1:
break
case 2:
break
case 3:
filter = arguments[1]
default:
filter = arguments[1]
print (filter)
}
print (filter)
And this prints out:
4
value
value
Which is exactly what it should print out. Remember the initialization of filter.
Update 2:
This is what you´re trying to do, your other result was always return 4 because that´s the count of arguments. Try the below code instead.
var filter = String()
func Usage() {
print("Usage: <filter> <input> [output]")
print("System filter paths do not need to be specified.")
return
}
let arguments = ["qwe", "value", "qwe", "asd"]
print(arguments.count)
for i in 0..<arguments.count {
switch i {
case 0:
Usage()
case 1:
Usage()
case 2:
Usage()
case 3:
filter = arguments[1]
default:
filter = arguments[1]
print (filter)
}
}
print (filter)
This prints out:
4
Usage: <filter> <input> [output]
System filter paths do not need to be specified.
Usage: <filter> <input> [output]
System filter paths do not need to be specified.
Usage: <filter> <input> [output]
System filter paths do not need to be specified.
value

Your code seems to be an entry point for a command line interface.
This is an alternative approach without declaring a global variable and without a switch.
Usage is printed if the number of arguments is less than 3 otherwise the first two arguments after the name of CLI (at index 0) are assigned to two variables.
let arguments = ["qwe", "value", "qwe", "asd"]
print(arguments.count)
if arguments.count < 3 {
Usage()
exit(EXIT_FAILURE)
}
let filter = arguments[1]
let secondArgument = arguments[2]
print (filter, secondArgument)
Then you could switch over the filter
switch filter {
case "value": doThis(with: secondArgument)
case "someOtherFilter": doThat(with: secondArgument)
default: doNothing()
}

Related

How to remove a variable from the field of view

while true {
print ( """
1. Log in
2. Create new user
3. Quit
""")
if let numberString = readLine(), let number = Int(numberString) {
print("you entered \(number)")
break
} else {
print("Try again")
}
}
It is necessary to use the number variable in the future to compare it.
How can it be taken out of sight?
When I try to make a global var something goes wrong:
var numberString: String?
var number: Int?
while true {
print ( """
1. Log in
2. Create new user
3. Quit
""")
if numberString = readLine(), number = Int(numberString) {
print("you entered \(number)")
break
} else {
print("Try again")
}
}
Considering that you are creating a command prompt and that choice has no meaning outside your loop there is no need to make it global. You only need to switch the user selection and decide what to do from there. Note that if you try to break from inside the switch you won't exit your loop as I showed to you in your last question. To allow the compiler to know that you want to break the while loop instead of the switch you need to label your while loop statement, this way you can specify what you want to break when you have a switch inside a loop. Try like this:
func getValue() -> Int? {
guard let line = readLine(), let value = Int(line) else {
return nil
}
return value
}
question: while true {
print("""
1. Log in
2. Create new user
3. Quit
""")
guard let value = getValue() else {
continue
}
switch value {
case 1:
print("you have selected number one")
case 2:
print("you have selected number two")
case 3:
print("Good bye")
break question
default:
print("Try again")
}
}
There is not much information to go off of here, but I think I can help. In the first script, you are creating a new variable and setting the value for that variable:
if let numberString = readLine(), let number = Int(numberString) { ... }
In your second script, you have to global variables, but at no point have you provided them a value. What you need to do is provide both global variables (numberString and number) a value before comparing them. As such, you need to use the == sign to compare different variables/ types. For instance:
var numberString: String?
var number: Int?
while true {
print("""
1. Log in
2. Create new user
3. Quit
""")
numberString = readLine()
number = Int(numberString!)
}
You can now compare and or print your global variables...
Final Code
var numberString: String?
var number: Int?
while true {
print("""
1. Log in
2. Create new user
3. Quit
""")
numberString = readLine()
number = Int(numberString!)
if number == 1 {
print("you have selected number one")
} else if number == 2 {
print("you have selected number two")
} else if number == 3 {
print("you have selected number three")
} else {
print("Try again")
}
}
Due to the fact that both variables numberString and number are now global variables, you can access them in the future if you need to compare them again.

Sort Array of JSON objects

I need to sort an array of JSON objects.
but it is needs to be translated from a literal meaning to a numeric meaning.
for example
object["status"]
"New" = 1
"Open" = 2
"Closed" = 3
/// I need to translated in here some where
var sortedOrders = orders.sort { $0["status"].doubleValue < $1["status"].doubleValue }
You could do this with an enum.
enum Status: Int {
case new = 1
case open = 2
case closed = 3
case unknown = 99
init(string: String) {
switch string {
case "new", "New": self = .new
case "open", "Open": self = .open
case "closed", "Closed": self = .closed
default:
self = .unknown
}
}
}
To use the enum, you could initialize like this:
var myStatus = Status(string: object["status"])
And use it like this:
print(myStatus) // prints "new"
print(myStatus.rawValue) // prints "1"
Edit: Since the enum has an underlying type of Int, to accomplish your sort you can compare the resulting Status directly (Thanks to this question https://stackoverflow.com/a/27871946/1718685):
var sortedOrders = orders.sort { Status(string: $0["status"]) < Status(string: $1["status"]) }
Here's one way:
let statuses = [ "New", "Open", "Closed" ]
var sortedOrders = orders.sort { (statuses.index(of: $0["status"] ?? "") ?? 99) < (statuses.index(of: $1["status"] ?? "") ?? 99) }
This will determine the index of each status within the statuses array. 99 will be used for unknown or missing statuses so any unknown statuses will appear at the end of the list.

Swift L-System Algae

So this is just something I'm doing for fun in the IBM Swift sandbox. I did a L-system algae in Scala recently and though it would be cool to do it in Swift to see how the language compares.
https://github.com/I2obiN/L-System-Algorithms-and-Fractals/blob/master/algae.scala
That's the Scala one to show you what I'm aiming for, and this is what I have in Swift;
/**
* Created by t.hood on 26/01/16
* L-System Algae
*
*/
import Foundation
// Mapping function for string
func stringmap(x: String) -> String {
var str = x;
// Replace characters in string
str = x.stringByReplacingOccurrencesOfString("A", withString: "AB") +
str.stringByReplacingOccurrencesOfString("B", withString: "A");
// Return mapped string;
return str;
}
func lsys() {
// Declarations
var iteration : Int = 2;
var x = 0;
var lsystem: String = "A";
let charA: Character = "A";
let charB: Character = "B";
while(x != iteration) {
print(lsystem)
// Iterate through characters in string
for chars in lsystem.characters {
lsystem = stringmap(lsystem);
}
// Inc count ..
x+=1
}
}
// Run ..
lsys();
The problem I'm having is in my mapping function. I need it to map x, print the result, then do the next map on str. The problem is I have the operator + between both maps and I can't get swift to print str after the first operation.
Anyone any ideas on how to get around this? If I could print str after the first replacements I think it would work.
I created a project in Xcode so I could use the debugger to see what's going on. Here's what I found.
I moved your print statement into the for loop so it would show the value of lsystem every time the loop executed.
The while loop executes twice, when x == 0 and 1
The first time through the while loop lsystem == 'A', so the for loop executes once. In stringmap(), the 'A' becomes 'ABA'.
'ABA' is printed.
The second time through the while loop, the for loop gets executed three times.
For loop 1: 'ABA' is sent to stringmap() and 'ABBABAAA' is returned.
For loop 2: 'ABBABAAA' is sent to stringmap() and 'ABBBABBABABABAAAAAAAA' is returned.
For loop 3: 'ABBBABBABABABAAAAAAAA' is sent to stringmap() and 'ABBBBABBBABBABBABBABABABABABABABABAAAAAAAAAAAAAAAAAAAAA' is returned.
I modified your stringmap() function to iterate through the string character by character and apply the grammar to each character, appending each change to a new string that was then returned to lsys().
Seven iterations of the while loop returned this, which agrees with what I see in the Wikipedia article about L-system.
Iteration 0: A
Iteration 1: AB
Iteration 2: ABA
Iteration 3: ABAAB
Iteration 4: ABAABABA
Iteration 5: ABAABABAABAAB
Iteration 6: ABAABABAABAABABAABABA
Iteration 7: ABAABABAABAABABAABABAABAABABAABAAB
Here's the code. This worked in a playground on my iMac, I'd expect it to work in the IBM Swift sandbox too.
func stringmap(x: String) -> String
{
var returnString = ""
for char in x.characters
{
switch (char)
{
case "A" :
returnString += "AB"
break
case "B":
returnString += "A"
break
default:
break
}
}
return returnString
}
func lsys()
{
// Declarations
let iteration : Int = 7;
var x = 0;
var lsystem: String = "A";
print("Iteration \(x): \(lsystem)")
while(x != iteration)
{
lsystem = stringmap(lsystem)
x++
print("Iteration \(x): \(lsystem)")
}
}
lsys()

Binary operator '~=' cannot be applied to two UmRet operands

I'm working on integrating an IDTech swiper into my app and I've gotten pretty far along, added the library, registered notifications, unregistered them, and now I'm working on a function that connects the reader. I can't seem to figure out what I'm doing wrong here when I'm attempting to switch cases based on a return value.. could someone please help me?
func displayUmRet(operation: String, returnValue: UmRet) {
var string = ""
do {
switch returnValue {
case UMRET_SUCCESS: string = ""
case UMRET_NO_READER: string="No reader attached"
case UMRET_SDK_BUSY: string="Communication with reader in progress"
case UMRET_MONO_AUDIO: string="Mono audio enabled"
case UMRET_ALREADY_CONNECTED: string="Already connected"
case UMRET_LOW_VOLUME: string="Low volume"
case UMRET_NOT_CONNECTED: string="Not connected"
case UMRET_NOT_APPLICABLE: string="Not applicable to reader type"
case UMRET_INVALID_ARG: string="Invalid argument"
case UMRET_UF_INVALID_STR: string="Invalid firmware update string"
case UMRET_UF_NO_FILE: string="Firmware file not found"
case UMRET_UF_INVALID_FILE: string="Invalid firmware file"
default: string="<unknown code>"
}
} while (0)
// var retStatus = UMRET_SUCCESS==ret
//self.textResponse.text = "\(operation), \(retStatus), \(string)"
self.hexResponse.text = "";
}
You need to put a . before your cases:
enum UmRet {
case UMRET_SUCCESS, UMRET_FAILURE
}
var string = " "
let returnValue = UmRet.UMRET_SUCCESS
switch returnValue {
case .UMRET_SUCCESS: string = "y"
case .UMRET_FAILURE: string = "n"
}
Also, 0 isn't the same as false in Swift, so:
do {
...
} while (0)
Shouldn't work either.
And you don't need semicolons at the end of a line, so this:
self.hexResponse.text = "";
can be this:
self.hexResponse.text = ""
And finally, if your switch statement has every case for every case in your enum, you don't need a default case. (that's why mine didn't have one in the example)
By the way, ~= is just the operator for the pattern-matching function, which is what Swift does in a switch statement. It works kind of like the == function, for instance, Int ~= Int is the same as Int == Int. But it's a bit more versatile: for instance Range ~= Int, eg 0...3 ~= 2 returns whether or not the Int is in the range. (So true in this case) For enums, it matches cases to cases. In my example, it'll match UMRET_SUCCESS, and string will be set to y.

How would I create a constant that could be one of several strings depending on conditions?

I want to have a constant using let that may be one of several values.
For instance:
if condition1 {
constant = "hi"
}
else if condition2 {
constant = "hello"
}
else if condition3 {
constant = "hey"
}
else if condition4 {
constant = "greetings"
}
I'm not sure how to do this with Swift and the let feature. But I'm inclined to believe it's possible, as this is in the Swift book:
Use let to make a constant and var to make a variable. The value of a constant doesn’t need to be known at compile time, but you must assign it a value exactly once.
How would I accomplish this?
As pointed out in the other answers you can't directly do this. But if you're looking to just variably set the initial value of a constant, then yes, that is possible. Here's an example with a computed property.
class MyClass {
let aConstant: String = {
if something == true {
return "something"
} else {
return "something else"
}
}()
}
I think you are looking for variable which will be assigned later inside switch-case:
let constant :String
switch conditions {
case condition1:
constant = "hi"
case condition2:
constant = "hello"
case condition3:
constant = "hey"
case condition4:
constant = "greetings"
default:
constant = "salute"
}
One option would be something like this, using a closure:
let constant: String = ({ value in
if conditionOne {
return "Hi"
} else if conditionTwo {
return "Bye"
}
return "Oops!"
})(myData /*needed for condition*/)
Or, for another twist, using generics:
func fancySwitch<S, T>(val: S, fn: S -> T) -> T {
return fn(val)
}
let x: String = fancySwitch(3) { val in
if val == 2 {
return "Hi"
} else if val < 5 {
return "Bye"
}
return "Oops"
}
let y: String = fancySwitch((3, 4)) { (a, b) in
if a == 2 {
return "Hi"
} else if b < 5 {
return "Bye"
}
return "Oops"
}
I understand what you're looking for. In Scala and some other functional languages this can be done using the match statement (kind of like switch) because the entire statement resolves to a value like this:
val b = true
val num = b match {
case true => 1
case false => 0
}
This is unfortunately not directly possible in Swift because there is no way to get a value from a branch statement. As stated in the Swift book, "Swift has two branch statements: an if statement and a switch statement." Neither of these statements resolve to a value.
The closest code structure I can think of is to first use a variable to retrieve the correct value and then assign it to a constant to be used in any later code:
let b = true
var num_mutable: Int
switch b {
case true:
num_mutable = 1
default:
num_mutable = 0
}
let num = num_mutable
Just add the line let constant: String before your if/else statement.
Below, an excerpt from Swift 1.2 and Xcode 6.3 beta - Swift Blog - Apple Developer elaborates.
let constants are now more powerful and consistent — The new rule is
that a let constant must be initialized before use (like a var), and
that it may only be initialized, not reassigned or mutated after
initialization. This enables patterns like:
let x : SomeThing
if condition {
x = foo()
} else {
x = bar()
}
use(x)
This formerly required the use of a var even though there is no
mutation taking place. Properties have been folded into this model to
simplify their semantics in initializers as well.
I found the Swift blog post above from the article "Let It Go: Late Initialization of Let in Swift", which I found by googling: swift let constant conditional initialize.