Lost your password?

"I love this game! Great graphics and gameplay!" ***** 
- Bobo1976 (Wordology - Canadian App Store)

A Simple Tip To Avoid Crashes

By Dave Wood on
Dave Wood
Owner/President of Cerebral Gardens
User is currently offline
Dec 03'11 Category iDevBlogADay 5 Comments

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.


This post is part of iDevBlogADay, a group of indie iPhone development blogs featuring two posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, or Twitter.

Tags: Tips & Tricks, Objective-C, XCode, iOS, iDevBlogADay

Comments

Guest
Hollance Sunday, 04 December 2011 00:22 · Edit Reply

Some bugs in your code

The ideas you present are good but I think there are a few mistakes in the code you pasted. You're making a copy of the array but then you don't enumerate through that copy but the original array. You do that in both examples so it's probably a copy-paste error. ;-)

Guest
Don Sunday, 04 December 2011 02:18 · Edit Reply

C/P error?

Shouldn't you be enumerating copyOfObjects instead of self.object? I fail to see how this would work otherwise.

Dave Wood
Dave Wood
Owner/President of Cerebral Gardens
User is currently offline
Dave Wood Sunday, 04 December 2011 04:48 Reply

Thanks

@Hollance @Don Thanks for catching my copy and paste errors. Fixed the entries.

Guest
Split Sunday, 04 December 2011 12:55 · Edit Reply

Copy

How do you know copy is thread safe operation?

Guest
Irwin Sunday, 04 December 2011 16:58 · Edit Reply

Thread Safety

While this is indeed correct for modifying a collection's contents in a loop on a single thread, this is still broken in the multithreaded case. What happens if the collection is modified while copying? This just pushes the error up another level, and may even be worse since -copy probably doesn't throw an exception on mutation (since the Foundation collections aren't designed to be thread-safe) and might silently corrupt data.

What you really should be doing for thread safety is to either wrap the -copy (if the collection contents themselves are immutable or thread-safe) or the entire loop (if they're not) in a lock or serial dispatch queue.

Leave your comment

Guest
Guest Saturday, 19 May 2012 14:34

Follow us on Twitter

@ItsTheFitz Hi, I think you just left a review for Party Doodles on the App Store, if so, please get in touch with me http://t.co/Awm4aJcB


A @PartyDoodles review in French: http://t.co/jXaQJrDF Google translation: http://t.co/7btzy4DO Pretty funny if the translation is accurate


@_MattWelch_ Glad we finally released the game for you (been in the works since last August!). Please let me know how much fun you have!


Our first review! Thanks @iLounge - Party Doodles combines the iPad and Apple TV into a party game | iLounge News: http://t.co/v4axb5g7