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.

RIP Steve Jobs (1955-2011)

RIP Steve Jobs

Steve,

Thanks for everything you've done to improve this world.  Thanks for giving us a platform with which to build a business, a career, and a life that's truly fulfilling.

You'll be missed.

Tags:

A Year From Now

Hello again iDevBlogADay readers!

For those that are unaware, Cerebral Gardens has been pretty much a one man shop since it's inception. Well, more like an eighth of a man shop since I've had a full time job the entire time. Earlier this month, I came across a quote:

A year from now you may wish you had started today.
-Karen Lamb

After reading it, I thought to myself, 'self, I wish I had started more than a year ago actually', and so I knew it was time.

As of October 1st, Cerebral Gardens will become a whole man shop! Plus a woman of course to keep me focused; someone has to crack the whip, and she's way more organized than I.

We have some exciting products that we'll be able to finish and bring to market soon. Plus, I'll be able to spend a bit of time writing more blogs for iDevBlogADay (ones more relevant to you than this one was).

If you're the type of person that likes to be inspired by quotes, you can check out a simple app I built a while ago to test Apple's push notifications. Carpe Diem. Message me if you'd like a promo code, I'll give them out in the order requested.

Add the Power of Dropbox to Every App

Ok, maybe not every single app, but if your app has any sort of data, then yes, you should add Dropbox support to the app. Certainly if the app is a tool of some sort, you understand that the user values the data that has been generated; but even if the app is a game, the user still values that data! If they've spent 5 hours to complete a tonne of levels, it's nice to have that accomplishment backed up, or available on a second device. This is where Dropbox comes in.

If you've been living under a rock and don't know what Dropbox is, it's a service that allows users to create a special folder on their computer that automatically syncs itself to the Dropbox servers and then any other computers also using the same account. This provides the user with a cloud based backup service (with a basic version control too). Using the official Dropbox iOS, Android and Blackberry apps, the user can access any of the files in their Dropbox account on the go. Sounds simple, and it is. So simple that everyone should be using it (especially since the basic service is free).

So how can you use this magical service in your apps? Dropbox provides an SDK for developers that lets you access a user's Dropbox account (with their permission of course). Now it's up to you to implement a solution to use it.

Before I go into detail on using the SDK (a future post), I'm going to suggest a directory hierarchy that we all follow. Remember that the root folder of the Dropbox is actually a directory on the user's computer that they're using. We don't want to clutter that folder with all kinds of stuff the user doesn't understand, they're likely to delete it.

One of the first apps I used that was Dropbox enabled was 1Password (An awesome app by the way). Their solution was to create a file called

.ws.agile.1Password.settings

in the root folder that only contained the location of their actual data. This lets users store their data wherever they want (provided it's still under the main Dropbox folder), and 1Password can still find it. There's a problem with this though, when you have lots of apps installed, all using a similar plan, you're going to have a tonne of junk in the root folder. Not user friendly at all. Not to mention, that while Mac OS X will hide a file starting with a dot by default, some of your users might not have switched from Windows yet and Windows will show the 'hidden' file in the folder, just waiting to be deleted.

My proposal, is that we create a folder in the Dropbox root called

.apps

as a central repository for third party app data. From there you use a reverse domain name system similar to your bundle id, but instead of dots, use new directories, and only use lowercase. So keeping with the 1Password example, they would store their data in

.apps/ws/agile/1password/

This will be consistent for their iPhone, iPad, Android, Mac OS X and Windows clients. All of their 1Password apps will be able to find the data regardless of system being used. Any data that is system specific can be stored further down the hierarchy.

This system should keep everything clean, organized and out of view of the user. Windows users will still see the .apps folder but at least it's just one folder and it's name should make it's meaning clear to most users.

Be aware that because you're now backing up your user's data to their Dropbox, they can now easily browse (and even modify) that data if they're so inclined. So make sure you protect this data if it shouldn't be seen or modified. For example, if you're game has 10 levels and you have to complete them in order to advance to the next one, don't record level completion in a simple format that lets the user effectively just check off that they've completed a level. If reading the data is ok (high score list etc), you can still use a simple format to store the info, just add some sort of validation to ensure the file hasn't been modified. A hash file will probably be fine for most simple cases (use some salt that you're keeping secret).1

Update (added this paragraph that was accidentally cut during my editing phase): Why bother using Dropbox in your app when iTunes backs everything up during a sync anyway? Well there are lots of reasons:

  • Not everyone syncs on a regular basis; shocking I know
  • If a user deletes an app, it deletes the data too, next sync, the backup is deleted too, if the user decides to put your app back on their phone, they have to start from scratch
  • Using Dropbox allows multiple devices to access the same data, play a game on your iPad, and continue later on your phone
  • It may be your app, but it’s the users data, so making it easy for them to access is a good thing

1 Note that the above point about checking for modified data files etc is vital even if you're not syncing to Dropbox, it's trivial for users to access/modify your data files through jailbreaking or even iTunes backups. Another issue is that the Dropbox folder is exposed to unknown other apps that might try to use the data contained within maliciously, scan for emails to spam, or account passwords etc. Those apps could be Windows malware etc so definitely encrypt sensitive data.

Will iOS 4.3 Change the App Store Ecosystem?

All indications point to the imminent release of iOS 4.3, if not this week, then certainly by next week. As always with new releases, a host of new features will be included, not just for users, but also for developers.

The rumour is that 4.3 will introduce subscription pricing options to the app store. This is in response to newspaper and magazine publishers looking for better pricing options for daily, weekly and/or monthly editions. But, who says subscriptions need to be limited to publications. Apple's Terms of Services don't. More on that in a bit.

One of the challenges of iOS development is earning enough revenue to make a living. It's been said that there are two app stores, App Store A, where you sell apps with mass market appeal, hoping to generate a lot of revenue in a very short time, and App Store B where you sell apps that target a narrower audience, aiming to generate a steady revenue stream for years.

App Store A is often compared to buying a lottery ticket, and has just recently made an appearance in Dilbert.

Dilbert.com

App Store B is considered to be the more attainable, long term success strategy. Since you're aiming at a narrower target market, it helps to be able to generate recurring revenue from your users.

I've long wanted to try charging a monthly or yearly fee to use an app, something that will support the development process after the initial sale. Every other software platform allows you to charge for upgrades in order to generate some recurring revenue from your installed user base. A few apps on the App Store have phased out the original version and released a new version, with a new charge. There a few problems with this approach, a) users who buy the app just before the switch, kind of get screwed, b) there's no easy way for a user to transfer their data from version 1 to version 2 (it can be done, but you have to build in a solution, unlike normal app upgrades), c) not all users of version 1 will even know version 2 is available.

Another option is to add new features and charge for them though in-app purchases, then a user can decide if the new features are worth the extra money to them, if not, no harm, they keep using the app as they bought it.

Back to the new subscription option. With subscription pricing there will be a new opportunity to generate recurring revenue from your user base. And to the user, it will be a well defined, easily understood method. $x per time period. Just like paying your monthly phone bill, or a yearly magazine subscription. You can cancel at any time, or keep paying and take advantage of all new features as they're released. For developers, you now have recurring revenue. Earnings to enable you to continue to maintain and support the app, while still feeding your kids.

There's no indication yet what the options will be from Apple, but it's a good guess that the same pricing tiers we're using now will apply, and that you'll be able to select from a variety of time periods, likely: weekly, bi-weekly, monthly, quarterly, yearly. As an example, you'll be able to charge $0.99 a quarter, instead of a one time fee of $2.99. If the user doesn't like your app, they save money. If they like the app, and continue to use it, you'll break even after 3 quarters, and earn more for the entire length of time the user uses your app.

The largest obstacle I foresee moving to this model will be the blow back from customers. The current app ecosystem has bred a sense of entitlement where users (not all, but a lot), feel they deserve an app, all future updates, full support etc, all for the low cost of $0.99. For most developers, and most apps, this isn't sustainable. Using a subscription will help solve this. As more of us developers begin to use this model, customers will begin to accept it and most likely actually prefer it, since they'll know exactly what they're getting and for how much, and their apps will constantly improve at no additional cost. And, all things considered, they'll still be getting their apps at a ridiculously low price.

Update: Apple officially released the information on subscriptions today. Subscription term lengths are: weekly, monthly, bi-monthly, quarterly, bi-yearly or yearly. Thanks Apple for giving developers more opportunity to become profitable!


iOS 4.3 is currently available as a beta and thus is under an NDA. Nothing I discuss here is covered under the NDA to my knowledge as there's been no official word about subscriptions other than the now public iTunes Terms and Conditions. If you feel I have disclosed something in the NDA, please let me know and I'll edit the post accordingly.