I'm rewriting a code from java to swift and need to break a multi-layered switches right way. In Java it looks like :
block0 : switch (topSwithch) {
case one: {
switch (innerSwitch) {
case insideCase: {
if (something){
break block0;
}
// etc
So, I'm breaking one switch from another. How do I do it in swift ?
This is what it'd look like in Swift. I did this in a playground with hardcoded values for the variables:
let topSwitch = 1
let innerSwitch = 4
let one = 1
let insideCase = 4
let something = true
block0 : switch (topSwitch) { //first switch labeled "block0", switching on topSwitch
case one: //topSwitch is 1, one is 1
switch (innerSwitch) { // switching on innerSwitch
case insideCase: // both are 1
if (something){ // if true
break block0; // break from "block0"
}
default: break // else
}
default: break // else
}
Related
I have the code below written in my program, but I was wondering if someone could help me structure in a more summarized way as using 'case' or 'caseif' from other languages.
var imagePressed: UIImageView
imagePressed = self.redImage
if color == 1 {
imagePressed = self.redImage
}
if color == 2 {
imagePressed = self.orangeImage
}
if color == 3 {
imagePressed = self.yellowImage
}
if color == 4 {
imagePressed = self.greenImage
}
imagePressed.alpha = 0.5
I would suggest to use Dictionary to avoid much code:
let images = [1 : redImage, 2 : orangeImage, 3: yellowImage, 4: greenImage]
if let image = images[color] {
imagePressed = image
}
Also consider replacing hardcoded numbers with a enum for color e.g.:
enum Color {
case red
case orange
...
}
Swift also provides the switch statement.
You could simply type
var imagePressed: UIImageView
switch color {
case 1: imagePressed = self.redImage
case 2: imagePressed = self.orangeImage
case 3: imagePressed = self.yellowImage
case 4: imagePressed = self.greenImage
default: // provide any default value
}
Note that Swift switch statement has no implicit fallthrough. That mean, if any case is matching, the code flow breaks there.
Use comma-separated conditions to match multiple cases.
I recommend to read the switch statement in their language guide:
https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html#ID129
Your syntax is quite inefficient anyway because the code checks always all conditions even if color is 1.
A better form is if - else if
var imagePressed : UIImageView
imagePressed = self.redImage
if color == 1 {
imagePressed = self.redImage
} else if color == 2 {
imagePressed = self.orangeImage
} else if color == 3 {
imagePressed = self.yellowImage
} else if color == 4 {
imagePressed = self.greenImage
}
imagePressed.alpha = 0.5
In this particular case I recommend to use a switch statement and drop the extra variable
switch color {
case 1: self.redImage.alpha = 0.5
case 2: self.orangeImage.alpha = 0.5
case 3: self.yellowImage.alpha = 0.5
case 4: self.greenImage.alpha = 0.5
default: break
}
Well...here is the code
func howMany() -> Int {
return 10
}
func Call() -> Void {
guard case let output = howMany(), output > 5 else { return }
}
Call()
I do not really understand how the guard case works. This looks pretty much like a pattern matching condition where we compare whether the result of howMany() is equal to output, if it is, assign the value to output and then compare it to the literal value 5. However, when I deleted the line of output > 5, the compiler said, "the guard condition is always true, body is unreachable."
According to the pattern, if we translate it into a switch statement, it looks pretty much like this
switch howMany() {
case let output where output > 5:
break;
}
The question is if it could be directly translated into the switch statement, then there should not be a warning of "the guard condition is always true, body is unreachable" when we delete the where condition.
I hope somebody could shed some light on this.
Consider:
func foo() {
guard case let output = howMany(), output > 5 else {
print("less than or equal to 5")
return
}
print("\(output) is greater than 5")
}
That is roughly equivalent to:
func bar() {
switch howMany() {
case let output where output > 5:
print("\(output) is greater than 5")
default:
print("less than or equal to 5")
return
}
}
If you remove that > 5 criteria:
func foo() {
guard case let output = howMany() else {
print("less than or equal to 5")
return
}
print("\(output) is greater than 5")
}
You get your warning:
'guard' condition is always true, body is unreachable
That warning is correct, because the body is unreachable.
And if you do the equivalent in the switch example:
func bar() {
switch howMany() {
case let output:
print("\(output) is greater than 5")
default:
print("less than or equal to 5")
return
}
}
If you do that, you will receive an analogous warning:
default will never be executed
And, again, it makes sense, because default will not be reached.
Now, consider your example switch with no default clause:
func bar() {
switch howMany() {
case let output:
print("output:", output)
}
}
You don't receive a warning here only because there is no default clause (the analog of the "body" of the guard statement).
This question already has answers here:
Swift switch pattern matching with arrays
(3 answers)
Closed 6 years ago.
I want to put my array of values as a case for my switch statement
I have an array of values say
let intValues = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 .... 100]
and I want to use a switch statement to be used as a comparison tool like so.
let inputValue = 30 // or some other int value
switch inputValue {
case 101:
// do something lol
/* =============================== */
case intValues: //
// do something more:
/* =============================== */
case 13131:
// do another thing
default:
// do default
}
I know I can do this easily by either doing this case 1, 2, 3, 4, 5, and so on or by using an if statement like so:
if intValues.contains(inputValue) {
// do something more:
} else if inputValue == 101 {
// do something lol
} else if inputValue == 13131 {
// do another thing
} else {
// do default
}
or by doing somethig like
if intValues.contains(inputValue) {
// do something more:
} else {
switch inputValue {
case 101:
// do something lol
case 13131:
// do another thing
default:
// do default
}
}
and vice versa
But is it possible though? to do it with just a switch statement?
You can use case let with where for that.
let intValues = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
let inputValue = 30 // or some other int value
switch inputValue {
case let x where intValues.contains(x):
// do something more:
case 101:
// do something lol
case 13131:
// do another thing
default:
// do default
}
You can do this with range operator.
let inputValue = 30
switch value {
case 1...100:
print("between hundred")
case 101:
print("it's 101")
default:
print("outer value")
}
You should just use a countable closed range in your switch cases:
let inputValue = 30
switch inputValue {
case 1...10:
print(1...10)
case 11...20:
print(11...20)
case 21...100:
print(21...100) // "21...100\n"
default:
print("default")
}
Swift 2's guide mentions that you can end program execution of an if statement. I personally have never used break with if-statement.
A break statement ends program execution of a loop, an if statement,
or a switch statement...When a break statement is followed by the
name of a statement label, it ends program execution of the loop, if
statement, or switch statement named by that label.
In what situation would one be using break in an if-statement? This language feature seems useless.
TEST:
if (true) {
break TEST
}
For example if you want to describe a number (with Strings) with reference to sets of numbers (even/rational/negative numbers) your code could look something like this:
if condition1 {
// code
if condition2 {
// code
if condition3 {
// code
if condition4 {
//code
}
}
}
}
You can achieve the same logic but without the nested ifs by refactoring it (using guard):
OuterIf: if condition1 {
// code
guard condition2 else { break OuterIf }
// code
guard condition3 else { break OuterIf }
// code
guard condition4 else { break OuterIf }
// code
}
// reads even better when breaking out of "do"
scope: do {
guard condition1 else { break scope }
// code
guard condition2 else { break scope }
// code
guard condition3 else { break scope }
// code
guard condition4 else { break scope }
// code
}
You might think that this can also be achieved with switch and fallthrough but this doesn't work with "normal" cases because it checks all conditions and if one condition is met all following conditions aren't even evaluated.
So the fallthough has to be called conditionally.
This does work but I isn't very readable not to mention its "beauty":
let x = 4
switch x {
case _ where condition1:
// code
if condition2 { fallthrough }
case _ where false:
// code
if condition3 { fallthrough }
case _ where false:
// code
if condition4 { fallthrough }
case _ where false:
// code
break
default: break
}
Using break with an if statement seems a bit contrived, and I can't think of a place where style would demand it. It does, however, save an extra level of indentation when skipping the latter portion of an if statement in an if-else clause, which can be useful for deeply nested loops.
In other languages, a popular (and/or controversial) idiom is to use labels for handling errors in deeply nested functions. For example, one might want to break out of a loop on error, like this:
func testBreak3() {
// doesn't compile!!!
let a = false, b = true, x = 10, y = 20, err = true
if !a {
if b && x > 0 {
if y < 100 {
if err {
break handleError
}
// some statements
} else {
// other stuff
}
}
}
return // avoid error handling
handleError:
print("error")
// handle the error
}
But in Swift (I'm using 2.0 as a reference), labels are different than with other languages; the above example doesn't compile for two reasons: The label isn't declared yet when it's used, and the label must be directly associated with a do, while, if, or case statement. Furthermore, break within an if or do statements requires that statement to be labeled. We can fix this as follows, although the changes make the solution less attractive due to additional tracking via the errorFlagged variable, making refactoring more attractive:
func testBreak() {
let a = false, b = true, x = 10, y = 20, err = true
var errorFlagged = false
nestedIf: if !a {
if b && x > 0 {
if y < 100 {
if err {
errorFlagged = true
break nestedIf
}
// some statements
} else {
// other stuff
}
}
}
// skip handling if no error flagged.
if errorFlagged {
print("error")
// handle error
}
}
I know this is old topic, but just now I used break and it was needed.
So my example
I have array of objects.
When user taps on a cell, i.parameter becomes True for the object in that cell.
I need to know when all the objects in the array have i.parameter = True , that's the condition to stop the game.
func forTimer(){
for i in array {
if i.parameter == false {
break
}
}
}
timer = Timer.scheduledTimer(timeInterval: 0.001, target: self, selector: #selector(forTimer), userInfo: nil, repeats: true)
Even if one i.parameter = false, I do not need to check the rest of the array.
This function is called every millisecond, so I will not have to check the whole array every millisecond.
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.