Iqbal Khan
Iqbal Khan

Reputation: 4617

Collection <CALayerArray: 0x1ed8faa0> was mutated while being enumerated

My app crashes some time while removing wait view from screen. Please guide me how can i improve code given below.


The wait view is only called when app is downloading something from server. and when it completed download then i call removeWaitView method.

Exception Type: NSGenericException

Reason: Collection was mutated while being enumerated.

+(void) removeWaitView:(UIView *) view{
    NSLog(@"Shared->removeWaitView:");
    UIView *temp=nil;
    temp=[view viewWithTag:kWaitViewTag];
    if (temp!=nil) {
        [temp removeFromSuperview];
    }
}

my waitview adding code is

 +(void) showWaitViewInView:(UIView *)view withText:(NSString *)text{
   NSLog(@"Shared->showWaitViewWithtag");
   UIView *temp=nil;
   temp=[view viewWithTag:kWaitViewTag];
   if (temp!=nil)
   {
       return;
   }
   //width 110 height 40
   WaitViewByIqbal *waitView=[[WaitViewByIqbal alloc] initWithFrame:CGRectMake(0,0,90,35)];
   waitView.center=CGPointMake(view.frame.size.width/2,(view.frame.size. height/2) -15); 
   waitView.tag=kWaitViewTag;    // waitView.waitLabel.text=text;
   [view addSubview:waitView];
   [waitView release]; 
}

Upvotes: 10

Views: 8771

Answers (4)

Roberto Piccirilli
Roberto Piccirilli

Reputation: 1

To fix issue just start from last element

NSMutableArray* Items = [[NSMutableArray alloc] initWithArray:[_ScrollList.documentView subviews]];
while ([Items count]>0) {
    NSView *v = [Items lastObject];
    [v removeFromSuperview];
    [Items removeLastObject];
}

Upvotes: 0

Spartak
Spartak

Reputation: 149

You should get a copy of the array, so you don't risk the chance of it being modified while your code is enumerating it. Of course this leaves the chance that a new item may be added as a result of the mutation, thus your enumeration will miss that one array item. Here is an example specific to the title of your question:

[[viewLayer.sublayers copy] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            CALayer * subLayer = obj;
            if(subLayer == theLayerToBeDeleted){
                [subLayer removeFromSuperlayer];
            }

        }];

Upvotes: 6

Aaron Hayman
Aaron Hayman

Reputation: 8502

It's possible that you're adding or removing a the waitView while iterating through the waitView's siblings (it's superView's subviews). Check to see what methods call removeWaitView and showWaitInView to make sure the calling methods don't call the show/remove wait view methods from within a for loop iterating the wait view's siblings (the waitView's superview's subviews).

Upvotes: 3

Sulthan
Sulthan

Reputation: 130092

The exception is pretty clear - a collection (in this case something like an array) is being modified while it is also being enumerated.

In this specific case we are talking about array of layers, or better said, instances of UIView which are all backed up by layers.

The modifications happen when you are calling removeFromSuperview or addSubview. The enumeration can happen anytime during redrawing.

My guess is - you are not calling your methods from the main thread and the main thread is currently redrawing, so you'll get a racing condition.

Solution: call these methods only from the main thread.

Upvotes: 18

Related Questions