ImmersionULTD ImmersionULTD - 4 months ago 4x
Swift Question

C-Style for loop works fine but changing to Swift for-in causes out of bounds errors

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
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.removeAtIndex(i) //the culprit?

Any help would be greatly appreciated.

I'd also like an explanation why the loops behave differently if possible.


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.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 {
              return false //don't keep this cheese
          else {
              return true //keep this cheese