So I have this simple for loop that causing me major aggravation. See, it works just fine using a C-Style for-loop (commented). But swift throws a warning (not an error) that C-Style loops are going to be depreciated in the future, so I figured I should change it.
When I try changing it, however, I get an out of bounds
error which never happened with the C-Style loop. The error occurs at the if
statement (so only if the mouse is over the cheese). And I don't see why it should work with a C loop and not a for-in loop.
func checkCheese(){
//for(var i = 0; i < cheese.count; i += 1){
for i in 0 ..< cheese.count {
print(i) //prints just fine every time
if CGRectIntersectsRect(mouse.node.frame, cheese[i].node.frame) {//throws the out of bounds error
cheese[i].node.removeFromParent()
cheese.removeAtIndex(i) //the culprit?
}
}
}
Any help would be greatly appreciated.
I'd also like an explanation why the loops behave differently if possible. Thanks
cheese.count
is only being evaluated once. Suppose you start with 3 items in cheese
. The loop will iterate over indices 0
, 1
, 2
. If you remove item 1
, then the old 2
becomes the new 1
, and there is no longer an item at index 2
. However, the loop will continue to index 2
, just as it was set out to do from the beginning.
To fix this, every time you remove, deincrement your index:
for i in 0 ..< cheeses.count {
print(i) //prints just fine every time
if CGRectIntersectsRect(mouse.node.frame, cheeses[i].node.frame) {//throws the out of bounds error
cheeses[i].node.removeFromParent()
cheeses.removeAtIndex(i) //the culprit? ... no longer!
i -= 1 //fixed!
}
}
Now, that solves the error for the solution as you present it, but I propose a cleaner solution:
cheeses.filter{ cheese in
if CGRectIntersectsRect(mouse.node.frame, cheese.node.frame {
cheese.node.removeFromParent()
return false //don't keep this cheese
}
else {
return true //keep this cheese
}
}