Change an Int variable value in LLDB - swift

Environment: Xcode 11.3.1/Swift 5
Here is the function:
func lldbTest() {
var switchInt = 1
...// do something and set a break point here
if switchInt == 1 {
print("switchInt == 1")
} else if switchInt == 2 {
print("switchInt == 2")
}
}
I debug before enter the if statement, and I change switchInt to 2 in lldb
e switchInt = 2
p switchInt
(Int) $R4 = 2
but it still print "switchInt == 1"
result

I guess the behavior is because the compiler has already evaluated the if statement "if switchInt == 1" because there's no code that changes the value of switchInt before that line. I tried the below and was able to get the behavior desired.
var switchInt = 1
for i in 0..<10 {
switchInt = 0
}
if switchInt == 1 { -> Put a break point here and use (lldb) e switchInt=2
print("switchInt == 1")
} else if switchInt == 2 {
print("switchInt == 2")
}
Now execute the command p switchInt and it will have the value 2. Step through the breakpoint and it will print switchInt == 2.

Setting variables from the debugger in Swift is somewhat hit and miss. Because swift uses so many wrapped objects (Int's for instance are actually a "struct"), the compiler has to do a fair amount of optimization even at -Onone or the code will run unacceptably slowly.
The debugger is often told only about a shadow copy of the variable, and not the location that is actually being used in code. You can try various tricks like Felix suggests, but at present you're not guaranteed to succeed...
This is a known bug, but for technical reasons is one that is tricky to solve.

Related

Swift - for loop statement not taking an absolute value

Such a weird question, but I set up this code in a playground:
let currentNumber = "1999999999"
let absNumber = abs(Double(currentNumber)!)
var digitCount = 0
if absNumber > 999999999 {
for n in currentNumber {
if n.isNumber {
digitCount += 1
} else {
break
}
print(digitCount)
}
}
As written, this code gets evaluated and my for loop runs...however, if is set my string to "-1999999999", the for loop doesn't run. The absolute value of -1999999999 is 100% greater than 999999999, so what did I miss?
The thing you did not understand is the control flow operator. You can get the expected behavior just change a single line:
if n.isNumber {
digitCount += 1
} else {
break // here change to continue
}
to this:
if n.isNumber {
digitCount += 1
} else {
continue
}
However, I highly recommend you try LLDB in an Xcode Project, either a Commandline tool or app. The stepover tool is quite useful for such a logical problem.

Combine if statement and for loop such that loop only gets executed once per every execution of if statement in swift

I'm trying to understand swift and therefore try to come up with simple command line games: in this game a player has to guess a secret word within 6 attempts by typing something in the command line, but every time he gets it wrong, a statement prints the number of his wrong attempts:
let response = readLine()
if response != "secret word" {
for n in 1...6 {
print(n)
}
}
else {
print("you are right!")
}
Now I know that my code will print all lines once the condition is not true, but I'm looking for a way to only print one item out of the four loop for every if statement consecutively.
I think a while loop works pretty well. Maybe something like this:
print("Welcome to the input game!\n\n\n\n")
var remainingTries = 5
let dictionary = ["apple", "grape", "pear", "banana"]
let secretWord = dictionary.randomElement()
print("Please guess a fruit")
while remainingTries > 0 {
remainingTries -= 1
let response = readLine()
if response == secretWord {
print("You got it!")
remainingTries = 0
} else if remainingTries <= 0 {
print("Too bad, you lose!")
remainingTries = 0
} else {
print("Incorrect. Tries remaining: \(remainingTries)")
}
}

Rolling a dice in swift using a while function and printing results until the result is 1

I'm really new to Swift and I have a task asking me to create a while loop that simulates rolling a 6-sided dice repeatedly until a 1 is rolled. After each roll, print the value.
In just about every iteration I've tried over the last 2 hours I keep ending in an infinite loop that explodes Xcode.
Any help would be fantastic!
var dieRoll = Int.random(in: 1...6)
while dieRoll <= 6 {
print (dieRoll)
if dieRoll == 1 {
print ("You win!")
}
}
Got it to this point, it no longer runs endlessly but it acts weird and returns values of 1 without printing "You win!"
func dieRoll(x: Int) -> Int {
return Int.random(in:1...6)
}
while dieRoll(x: 0) > 1 {
print(dieRoll(x: 0))
if dieRoll(x: 1) == 1 {
print("You win!")
}
else {
RETURN
}
}
Your dieRoll variable is declared AS A VARIABLE yet you never change it! Try “rerolling” within the While Loop
Also, there’s always the chance that a 6 never gets rolled... idk if you want to mess with “real” probabilities but if you’re finding issues you may want to institute a “max number of rolls”... personally I wouldn’t but hey you never know
TDLR: last line of the while-loop should reroll your dieRoll var
Okay, so I got away from the string text and focused on what the code was saying versus what my typing was saying. Ended up with this (probably a monstrosity to you experienced folks) but it looks something like this.
var rolling = Int.random(in: 1...6)
while rolling > 1 {
print(rolling)
if rolling == 1 {
break
} else {
rolling = Int.random(in: 1...6)
}
}
print(rolling)
And every time I run it it ends on a 1 so it does what it needs to!

Combining optional chaining and ifs

I found out, that I can write this code:
func optionalReturn() -> Int? {
// do sth. and return maybe an Int, otherwise:
return nil
}
if let x = optionalReturn(), x > 5 {
print("test exists and is greater then 5")
}
Now I'm standing in front of the following problem: I want to have an if, that handles two cases:
case 1: x is not existing, OR
case 2: x is existing, but is greater than value 5
This is not working:
if x == nil || (let x = optionalReturn(), x > 5) {
...
}
Is sth. like this possible in Swift?
UPDATE
The above code was simplified to show my problem, but my case is a little bit different, because my called function doesn't return an optional Int, it returns an optional struct:
struct TestStruct {
var x: Int
var y: Int
}
func optionalReturn() -> TestStruct? {
// do sth. and maybe return a TestStruct(....), otherwise:
return nil
}
let test = optionalReturn()
if test == nil || ...?
UPDATE 2
In my first update I had a mistake. Thanks to Christik, who mentioned it in the comments, my code had a mistake and would have worked without it. I accepted his answer as a solution, but my first idea was right as well: Swift skips the other if-conditions, if the first OR-condition is true. So this code works as well:
...
if test == nil || (test!.x > 5 && test!.y > 6) {
print("I am here")
}
You can use the nil coalescing operator here, and give x a value greater than 5, if its nil:
if (x ?? 6) > 5 {
// do your thing
}
In regards to the question update, you can use map on the optional to achieve your goal:
if x.map({ $0.x > 5 && $0.y > 6 }) ?? true {
// do your thing
}
map has the advantage that it avoids the forced unwrap.

Condition after variable binding in guard swift compilation issue

I am using the nice guard statement from Swift 3.0 (in Xcode 8.0) and have the following function:
func parse(suffix s: String) throws -> Instruction {
guard let count = Int(s) where count >= 0 else {
throw InstructionParsingError(message: s + " should be a positive integer")
}
return CallInstruction(argCount: count)
}
My issue is that the swift compiler complains twice about the line containing my guard statement:
CallInstruction.swift:42:29: Boolean condition requires 'where' to separate it from variable binding
CallInstruction.swift:42:30: Expected ',' joining parts of a multi-clause condition
I tried
replacing the where with a , then the second error disappears but the first one is still there.
replacing the where with , where but then this line can't even be parsed
replacing the count in the where by Int(s) but have the same errors.
How should I change my code so that it compiles? (With a nice single guard statement I mean, of course I could have multiple guards, or ifs or switch but from what I read about the guard statement I should be able to have a clean readable line).
For solving of this issue i recommend you to use model Swift syntax in guard statement that replace where with ,.
func parse(suffix s: String) {
guard let count = Int(s), count >= 0 else {
return
}
}
Also it is possible to use if let statement :
func parseTwo(suffix s: String) {
if let count = Int(s), count >= 0 {
// done
print(count)
} else {
return
}
}