Our BlogTips, Tricks, and Thoughts from Cerebral Gardens

A Simple Tip to Avoid Crashes

As you may be aware, I went full time indie a couple of months ago. I've been working almost as many hours as I can stay awake for clients, and spending whatever extra time I can find on a new game that I hope will be finished and submitted to the App Store before my next blog! I can't wait to tell you guys all about it.

With all this work though, I've been slacking in the blog department. Today I start to correct that. Here's a quick tip for today that may save you from a few crashes tomorrow.

It's a common sight to see something like this in Objective-C, where you're enumerating through an array (that's mutable), and doing something to each of the objects:

// self.objects is an NSMutableArray
for (NSObject *object in self.objects)
{
    [object doSomething];
}

If your app is multithreaded, you'll get a crash if another thread adds to or removes from the array at the same time this loop is being processed. Depending on timing, you might not see this bug hit until the app is being used by users.

Instead, anytime you're going to run through an array like this, make a copy first and enumerate the copy. Now you're multithreaded safe.

NSMutableArray *copyOfObjects = [self.objects copy];
for (NSObject *object in copyOfObjects)
{
    [object doSomething];
}
[copyOfObjects release]; copyOfObjects = nil;

Here's another common pattern you'll see, when you're enumerating the array in order to remove certain elements from it. Because you know you can't remove objects from the array as you're running through it, you create another array to store the the objects you want to remove and then remove them in a second step:

NSMutableArray *objectsToRemove = [[NSMutableArray alloc] init];

// self.objects is an NSMutableArray
for (NSObject *object in self.objects)
{
    if ([object shouldBeRemoved])
    {
        [objectsToRemove addObject:object];
    }
}
[self.objects removeObjectsInArray:objectsToRemove];
[objectsToRemove release]; objectsToRemove = nil;

Using the copyOf pattern above, you can remove the objects in a single step, since you're not actually enumerating the same array anymore:

NSMutableArray *copyOfObjects = [self.objects copy];
for (NSObject *object in copyOfObjects)
{
    if ([object shouldBeRemoved])
    {
        [self.objects removeObject:object];
    }
}
[copyOfObjects release]; copyOfObjects = nil;

Now you have nice, clean, efficient, crash free code.

Enumeration of NSMutableArray's Follow Up
RIP Steve Jobs (1955-2011)