Swift 2 - Use case for using break on if statement? - swift

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.

Related

Guard Case Assignment

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

Is there a way to make a signal similar to combineLatest without needing all the signals to initially fire?

I have an array of signals
var signals = [Signal<ActionResult?, NoError>]()
where
enum ActionResult
case failed
case pending
case completed
}
I want to create a combined signal that returns true if one or more of the signals fires a .pending
let doesAnyOfTheActionsLoad = Signal.combineLatest(signals).map { values in
values.reduce(false, { (result, nextResult) -> Bool in
if result == true { return true }
if case .pending? = nextResult {
return true
}
return false
})
}
My only problem is that the combineLatest will only fire if all signals have fired at least once, and i need my signal to fire regardless if all signals have fired. Is there a way to do this in ReactiveSwift?
Try this:
let doesAnyOfTheActionsLoad = Signal.merge(signals).map { $0 == .pending}
If you want the signal to stay true after one .pending, then you need to store the current state with something like the scan operator:
let doesAnyOfTheActionsLoad = Signal.merge(signals).scan(false) { state, next in
if case .pending? = next {
return true
}
else {
return state
}
}
scan is like the "live" reactive version of reduce; it sends along the current result each time a new value comes in and is accumulated.
The other solutions are technically correct but I thought this might fit your use case better.
// Only ever produces either a single `true` or a single `false`.
let doesAnyOfTheActionsLoad =
SignalProducer<Bool, NoError>
.init(signals)
.flatten(.merge) // Merge the signals together into a single signal.
.skipNil() // Discard `nil` values.
.map { $0 == .pending } // Convert every value to a bool representing whether that value is `.pending`.
.filter { $0 } // Filter out `false`.
.concat(value: false) // If all signals complete without going to `.pending`, send a `false`.
.take(first: 1) // Only take one value (so we avoid the concatted value in the case that something loads).

Swift 3 enum with associated value AND function comparison

I have this struct that has an enum property as well as a function:
struct UserInput {
enum State {
case unrestricted
case restricted(because: WarningType)
enum WarningType {
case offline
case forbidden
}
}
var config: UserInputConfig?
var state: State = .unrestricted
func isConfigured() -> Bool {
// Arbitrary checks about the config...
}
}
Is there a way to rewrite the following conditionals so that the check for isConfigured() and state are in the same statement?
if case .restricted = userInput.state {
return 1
} else if userInput.isConfigured() {
return 1
} else {
return 0
}
It seems because the State enum uses associated values, you cannot simply write if userInput.state == .restricted || userInput.isConfigured(), you need to use the if case syntax. There must be a way around this?
You would like to do this:
if case .restricted = userInput.state || userInput.isConfigured() {
return 1
} else {
return 0
}
but there is currently no way to do an OR with pattern matching. There are a couple of ways of doing AND.
By using DeMorgan's Laws, you can turn if a || b into if !(!a && !b) and by reversing the then and else clauses of your if statement, you can just check for if !a && !b.
Unfortunately, you can't say if !(case .restricted = userInput.state), but since your enum has only 2 cases, you can replace that with if case .unrestricted = userInput.state.
Now, how do you use that with another statement? You can't use && for the same reason you can't use ||.
You can check for the failing case by using a pattern that matches both failing conditions (which is using AND) and then return 1 if both failing conditions aren't met:
if case (.unrestricted, false) = (userInput.state, userInput.isConfigured()) {
return 0
} else {
return 1
}
Equivalently you can use a multi-clause condition:
if case .unrestricted = userInput.state, !userInput.isConfigured() {
return 0
} else {
return 1
}
In addition to being shorter and IMO easier to read, this second method can short circuit and skip calling userInput.isConfigured in the case where case .unrestricted = userInput.state fails.
You can do it really cleanly with a switch statement, and pattern matching:
switch userInput.state
{
case .unrestricted:
return userInput.isConfigured() ? 1 : 0;
case .restricted(_):
return 1
}

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.

Does a break statement break from a switch/select?

I know that switch/select statements break automatically after every case. I am wondering, in the following code:
for {
switch sometest() {
case 0:
dosomething()
case 1:
break
default:
dosomethingelse()
}
}
Does the break statement exit the for loop or just the switch block?
Break statements, The Go Programming Language Specification.
A "break" statement terminates execution of the innermost "for",
"switch" or "select" statement.
BreakStmt = "break" [ Label ] .
If there is a label, it must be that of an enclosing "for", "switch"
or "select" statement, and that is the one whose execution terminates
(§For statements, §Switch statements, §Select statements).
L:
for i < n {
switch i {
case 5:
break L
}
}
Therefore, the break statement in your example terminates the switch statement, the "innermost" statement.
A hopefully illustrative example:
loop:
for {
switch expr {
case foo:
if condA {
doA()
break // like 'goto A'
}
if condB {
doB()
break loop // like 'goto B'
}
doC()
case bar:
// ...
}
A:
doX()
// ...
}
B:
doY()
// ....
Yes, break breaks the inner switch.
https://play.golang.org/p/SZdDuVjic4
package main
import "fmt"
func main() {
myloop:
for x := 0; x < 7; x++ {
fmt.Printf("%d", x)
switch {
case x == 1:
fmt.Println("start")
case x == 5:
fmt.Println("stop")
break myloop
case x > 2:
fmt.Println("crunching..")
break
default:
fmt.Println("idling..")
}
}
}
0idling..
1start
2idling..
3crunching..
4crunching..
5stop
Program exited.
This question might be too old already but I still think label makes our code become harder to read.
Instead of breaking the for inside select, just set a flag for the loop and handle it inside select-case before invoking break.
For example:
loop := true
for loop {
select {
case <-msg:
// do your task here
case <-ctx.Done():
loop = false
break
}
}
Updated: Totally agree with Vaelin in the comment. Declaring that flag inside the scope of the for loop can avoid memory leak and conflict with other variables in current scope, just in case we have a same variable name already.
for loop := true; loop; {
}
Just from a switch block. There's plenty of examples in Golang own code you can examine (compare inner break with outer break).
this should explain it.
for{
x := 1
switch {
case x >0:
fmt.Println("sjus")
case x == 1:
fmt.Println("GFVjk")
default:
fmt.Println("daslkjh")
}
}
}
Runs forever
for{
x := 1
switch {
case x >0:
fmt.Println("sjus")
break
case x == 1:
fmt.Println("GFVjk")
default:
fmt.Println("daslkjh")
}
}
}
Again, runs forever
BUT
package main
import "fmt"
func main() {
d:
for{
x := 1
switch {
case x >0:
fmt.Println("sjus")
break d
case x == 1:
fmt.Println("GFVjk")
default:
fmt.Println("daslkjh")
}
}
}
will print sjus
... clear ?
http://play.golang.org/p/GOvnfI67ih
It only exits the switch block.