Question

I am creating an app that starts with a CGRect that is the size of the screen. when the users touches inside of the CGRect it is cut into two CGRects. I get this to work just fine when I touch inside of the new CGRect that is created, but when I touch within a CGRect that is not the latest one added to the rectangleArray the app crashes and says sigabrt.

Here is the code in touchesBegan, blockPoint is the point where the screen is touched

for (NSValue *val in rectangleArray){
    CGRect rectangle = [val CGRectValue];
    if (CGRectContainsPoint(rectangle, blockPoint)) {
        CGRect newRectangle;
        CGRect addRectangle;
        if (!inLandscape) {
            newRectangle = CGRectMake(rectangle.origin.x, rectangle.origin.y, rectangle.size.width, blockPoint.y - rectangle.origin.y);
            addRectangle = CGRectMake(rectangle.origin.x, blockPoint.y, rectangle.size.width, rectangle.size.height - (blockPoint.y - rectangle.origin.y));

        }
        else {
            newRectangle = CGRectMake(rectangle.origin.x, rectangle.origin.y, blockPoint.x - rectangle.origin.x, rectangle.size.height);
            addRectangle = CGRectMake(blockPoint.x, rectangle.origin.y, rectangle.size.width - (blockPoint.x - rectangle.origin.x), rectangle.size.height);
        }
        [rectangleArray replaceObjectAtIndex:[rectangleArray indexOfObject:val] withObject:[NSValue valueWithCGRect:newRectangle]];
        [rectangleArray addObject:[NSValue valueWithCGRect:addRectangle]];
    }
}

Why is this crashing?

Was it helpful?

Solution

You're trying to mutate the array (with "replaceObjectAtIndex:") while enumerating it (the "for loop" at the beginning of your code). This rises an exception. You should see it in the console log, something like this:

Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection  was mutated while being enumerated.

What you can do instead is to first enumerate, then identify the objects you want to mutate, store them in another collection class (a NSSet or another NSArray) and finally apply the collected items in the original array. Or another possibility is you make a copy of the first array, then enumerate the copy and do the changes to the original array.

OTHER TIPS

I had this problem before in my code, and let me guess, you have created the array in your init or initWith.... method, right?

To properly create a property with code (that is, not a UI control from Interface Builder) in init method, always retain your property.

In short,

myNSMutableArray = [[NSMutableArray alloc] initWith....];

should be

myNSMutableArray = [[[NSMutableArray alloc] initWith....] retain];

this way, even your init method ends, the retain count of myNSMutableArray will prevent the system to free/release your object.

Alternatively, since you declare the property in (retain) way, you can use

self.myNSMutableArray = [[NSMutableArray alloc] initWith...];

Using accessor will do the retain for you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top