Index Out of Range Error in Swift - swift

var numberOfPeople = 1 //get from host
var numberAtCounter = 0
func showNames() {
if peopleInMatch[numberAtCounter] == yourPeerID { //change to peopleinmatcheveryone
if numberOfPeople == 0 {
print("hoho")
personName.isHidden = true
connect.isHidden = false
connect.setTitle("PRESS READY", for: UIControlState.normal)
//change label to ready
} else {
numberAtCounter += 1
numberOfPeople -= 1 // buggy?
print("\(numberAtCounter)")
showNames()
}
} else {
personName.text = "TAKE PHOTO OF \(peopleInMatch[numberAtCounter])'s COLOR"
numberAtCounter += 1
if numberOfPeople <= 0 {
personName.isHidden = true
connect.isHidden = false
connect.setTitle("PRESS READY", for: UIControlState.normal)
//change label to ready
}
numberOfPeople -= 1 //buggy maybe fixed
}
}
I'm getting a Thread 1: EXC_BREAKPOINT error on the if peopleInMatch[numberAtCounter] == yourPeerID line. I'm not entirely sure what out of index means or what is potentially wrong. The code will be run through once then the function calls itself and on the second time through it breaks down on the line I mentioned above. I've checked all the variables and none of them are nill. Any ideas?

Here I made a short example for you to understand where your problem actually is.
ScreenShot 1:
Everything works fine when function is called for first time value at numberAtCounter is printed.
Here in first call either you are decrementing the value as numberAtCounter-=1 which take value from 0 to -1. Thus in second call when the function is called in line at:
if peopleInMatch[numberAtCounter] == yourPeerID // here you need to check value of `numberAtCounter`
make sure it's not getting a negative value or value more than your peopleInMatch array.
Thus if it becomes negative or more than count, result you will get as follows:

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)")
}
}

Xcode - changing the number of labels

Hello I am new to coding and in seek of help. Lately i've been trying to make it so in a label if it get's to a certain number in my case 8 it resets back to 0.
let label = UILabel()
var count: Int = 0 {
didSet {
if count == 8 {
count = 0
}
label.text = "\(count)"
}
}
all you need to do is to increment the count where you need, everything else is taking care of by the didSet - reseting count and updating label text.
increment your count as:
count += 1 // or the value you need

Having trouble with a while loop in Swift 5

Essentially, I'm making an app about a virtual dog to help people take care of their dogs. One of the screens gives you fifteen seconds to pet the dog five times. Whenever I try to load the screen, the app freezes. The code is inside of viewDidLoad()
while timesPetted < 5 {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: {
timer += 1
if timer == 15 {
self.failureLabel.isHidden = false
self.reset.isHidden = false
self.timesPetted = 0
}
})
}
When I delete the while loop, the screen loads normally and runs perfectly, but (obviously) there isn't a time limit. If I move the while loop out of viewDidLoad(), I get an error saying that Xcode "Expected declaration".
Either use a timer that is set to expire in 15 seconds
let timer = Timer.scheduledTimer(withTimeInterval: 15.0, repeats: false) { timer in
self.failureLabel.isHidden = false
self.reset.isHidden = false
self.timesPetted = 0
}
Or if you want to use DispatchQueue then use it only once
DispatchQueue.main.asyncAfter(deadline: .now() + 15) {
self.failureLabel.isHidden = false
self.reset.isHidden = false
self.timesPetted = 0
}
it appears the while loop is running infinitely due to the value of timesPetted. As the value of timesPetted is not changing at all once it enters the while loop.
To solve your issue you can make changes to your code as below :-
You must be updating your timesPetted value some where in the code.
lets say timesPetted is changed in function called "Petting", so when this function is called have check, which limits the user to pet till 5 times only and another check for 15 seconds. As shown below.
func petting() {
if reset.isHidden && timesPetted <= 5{ // here the reset.isHidden will become false in DispatchQueue (present in viewDidLoad) once the 15 seconds have been passed.
timesPetted += 1
}
}
And also make sure to add this line of code in your viewDidLoad.
DispatchQueue.main.asyncAfter(deadline: .now() + 15) {
self.failureLabel.isHidden = false
self.reset.isHidden = false
self.timesPetted = 0
}

Best way to check for all values in a Int

I don't know if there is a better way of doing this, my solution works but just seems to repetitive.
I have a life indicator which is represented using an icon within SpriteBuilder, these are set to not visible, and then within source I have implemented the following code:
lives = 3 // this is reduced or increased within game
if (lives == 5) {
lifeIcon1.visible = true
lifeIcon2.visible = true
lifeIcon3.visible = true
lifeIcon4.visible = true
lifeIcon5.visible = true
} else if (lives == 4) {
lifeIcon1.visible = true
lifeIcon2.visible = true
lifeIcon3.visible = true
lifeIcon4.visible = true
} else if (lives == 3) {
lifeIcon1.visible = true
lifeIcon2.visible = true
lifeIcon3.visible = true
} else if (lives == 2) {
lifeIcon1.visible = true
lifeIcon2.visible = true
} else if (lives == 1) {
lifeIcon1.visible = true
}
This works fine but just seems repetitive, and is difficult to scale if I wanted to increase the lives to more than 5 at a later date.
Any suggestions?
Assuming you want to set your visible to false when you decrease your lives, you can use something like this:
let lifeIcons = [lifeIcon1, lifeIcon2, lifeIcon3, lifeIcon4, lifeIcon5]
...
for (index, lifeIcon) in lifeIcons.enumerate() {
lifeIcon.visible = index < lives
}
Or if you like using closures:
lifeIcons.enumerate().forEach{$1.visible = $0 < lives}
(Here $1 is the current life icon in the iteration, and $0 is the index of that icon)
The key point here is to use an array, instead of multiple variables to keep track of your life icons. You can then iterate through this array, using the indices of the elements in order to determine which icon they are. enumerate() is used in order to create a lazy sequence of pairs of elements with their indices.
In this case we can compare the indices of the elements with the current number of lives. Because indices are 0 based, we can check whether a given index is less than the current number of lives in order to determine whether it should be visible.
How about this:
let icons = [lifeIcon1, lifeIcon2, lifeIcon3, lifeIcon4, lifeIcon5]
icons[0..<lives].forEach { $0.visible = true }
It is similar to #Adam Heeg's answer, but the c-style loops are in the process of being deprecated. I would slice the array by subscript and use forEach instead.
It seems like you have some other code which you don't wnat to change. I would suggest the following.
Load all your lifeIcon's into an array then do the following. (adjust for if you are 0 based or not).
for (int i = 0; i < lives; i++)
{
lifeIconArray[i].visible = true;
}