0

I am using a nsmutablearray in loop and want to remove its object (or assign nil) that has just traversed. But if I am doing so, I get an error as <__NSArrayM: 0x8c3d3a0> was mutated while being enumerated.' . The code is as below

- (TreeNode*)depthLimitedSearch:(TreeNode *)current costLimit:(int)currentCostBound {

NSMutableArray *children=[NSMutableArray arrayWithArray:[current expandNodeToChildren]];
for (TreeNode *s in children) {
    if (s.puzzleBox.isFinalPuzzleBox) {//checking for final puzzleBox
        return s;
    }
    /*exploredNodes++;
    if (exploredNodes %10000==0) {
        NSLog(@"explored nodes for this treshold-%d are %d",currentCostBound,exploredNodes);
    }*/

    int currentCost =[s.cost intValue]+[s.heuristicsCost intValue];

    if (currentCost <= currentCostBound) {
        //[s.puzzleBox displayPuzzleBox];

        TreeNode *solution = [self depthLimitedSearch:s costLimit:currentCostBound];
        if (solution!=nil){//&& (bestSolution ==nil|| [solution.cost intValue] < [bestSolution.cost intValue])) {
            bestSolution = solution;
            return bestSolution;
        }
    }else {
        if (currentCost < newLimit) {
            //NSLog(@"new limit %d", currentCost);
            newLimit = currentCost;
        }
    }
    // here I want to free memory used by current child in children
    [children removeObject:s]
}
children=nil;
return nil;
}

and I have commented the place where I want to release the space used by the child.

1
  • GO BACKWARDS -- an age-old programming trick. A fuller solution is how you do it in a database .. have another column (field, whatever) labelled please_delete_me, and proceed from there. Deletion is really complicated, in a broad sense, when you are dealing with threads, different consumers of the data, etc etc. Commented Jun 5, 2014 at 6:35

2 Answers 2

3

You should not be using a for...in loop if you want to remove elements in the array. Instead, you should use a normal for loop and go backwards in order to make sure you don't skip any items.

for (NSInteger i = items.count - 1; i >= 0; i--) {
    if (someCondition) {
        [items removeObjectAtIndex:i];
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

why should not use forward as it will always hold index x for object that will be there for sure because i am not doing anything with other object.
@Revinder: Assume the array has 10 elements and we are currently at index 3 and want to delete this index. We delete index 3, then the next iteration of the loop causes i to be 4. Since we deleted index 3 everything above it has been reindexed by -1. So now we are observing the item that was originally at position 5, and we have never looked at the item at position 4.
Hi @Revinder. It's an absolute basic of programming that when you do deletions, you have to work backwards. It's the first thing you learn in CompSci 001 ! :) Please listen to Senseful's excellent explanation.
hey @JoeBlow do you have knowledge about solving 15 puzzle using pattern database?
@Revinder. I'm sorry, I have no clue what you are talking about. Be sure to ask a new question for further questions, as this one is closed now.
1

You can collect the items to be removed in another array and remove them in a single pass afterwards:

NSMutableArray *toRemove = [NSMutableArray array];
for (id candidate in items) {
    if (something) {
        [toRemove addObject:candidate];
    }
}
[items removeObjectsInArray:toRemove];

It’s easier than iterating over indexes by hand, which just asking for off-by-one errors. Not sure how this plays with your early returns, though.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.