Escort Missions Logo

Escort Missions

You ever get the feeling that life is just one long series of Escort Missions?

“App Accomplished” Nearing Accomplishment

It’s been a long time since I’ve done much (really any) blogging, but hopefully that drought will be coming to an end soon. I’ve just turned in my 13th (of 14) chapters of my upcoming book, App Accomplished.

It’s been a lot of work. I knew it was going to be a huge time commitment, and I wasn’t wrong. There were many times I wondered if I would ever be done, but now that I can see the light at the end of the tunnel, it feels really good.

I’ve learned a lot in the process. Much of which I’ll be writing about here, since a) I’ve gotten used to doing a lot of writing, b) I won’t be spending all my writing time on the book, and c) blogging about the book will hopefully help people find out about the book.

So now it’s time to finish the final chapter (which, if you’re curious, is about submitting your app and planning the next version), and start the editing (and marketing) process.

It should be fun.

I Am Now Officially Writing a Book

I’ve been working on writing a book for some time now. It’s been through many stages, conversations, outlines, contracts, etc., etc. But for some reason, it never felt real, until now.

Oddly enough, the thing that made it feel real was that I found out the book has been issued an ISBN number. I’m not exactly sure why that made such a difference – maybe it’s all the years I’ve spent writing applications for which the unique ID in the database was the de-facto proof of existence. But in any case, it feels real now. I’m no longer worried that it’s going to fall through or that by announcing it I might be setting myself up for failure.

So there it is, I’m writing a book for Addison-Wesley Professional called App Accomplished: Strategies for App Development Success. The book has its own companion blog as well.

Although I’m a developer by trade and have spent my last few years as an iOS developer for hire, it’s not a programming book. It’s a book for a group I call App Creators: people that have an idea for an app that they want to have built, and are willing to take responsibility for making sure it ends up in the app store. Sure, some of them are coders, but many, if not most, are entrepreneurs or managers that don’t program. This book is for them.

I’m writing it because I’ve seen too many projects that failed because of a lack of knowledge or understanding. I’ve seen too many apps that could have been so much better if only requirements had been clearer, or features communicated better or decisions had been made earlier in the process.

I hope that, through it, I can keep some projects from failing that otherwise would have, and I can contribute to making some apps better that otherwise would have been worse.

There’s a lot of work between where I am (having just turned in my second of fourteen chapters) and the book being completed and published. But I’m very excited to go through that process, and I’m grateful to the folks at Addison-Wesley Professional for giving me the chance and helping me make the book a better one that what I could have written by myself.

Migrated From SquareSpace to Octopress

I’ve moved my blog from Squarespace to OctoPress.

I’ve gotten more and more frustrated with SquareSpace over the last couple of years. They moved to their new version 6 product, but it has no API access. This is a real annoyance for me, but SquareSpace doesn’t seem to care.

So my only options for adding content there are their buggy web interface, their even buggier iPad app, or stay on their old version 5, which is very buggy, and not getting any development resources.

So, I went in search of another blogging platform, and I decided on OctoPress. I tried a couple of others first, notably WordPress (via WPEngine), but trying to import my old blog content and have it show up at the correct old URLs was just too much work.

So I wrote this ruby script to convert my old content from SquareSpace to Octopress. There might be some glitches (like, I haven’t gotten comments set up), but I think I like it so far.

Finding Relevant WWDC Videos

As I’ve said before, I find the WWDC videos to be invaluable and I try watch all of them eventually. But there are a lot of them, and it can be hard to find what’s relevant. And a lot of them I go back and watch again when I start working with a different part of a project.

So I’ve developed a trick, and I thought I’d share it with you all.

I go to the site where the videos are hosted and click on the “view all in iTunes button”. From iTunes, I download all the slides (Click a track like “Essentials”, then click “Slides” just above the list, and then click the “Get Tracks” button in the header).

I keep all the slides for WWDC 2010, 2011 and 2012 in subdirectories of a folder named “WWDC slides” in my Documents directory. It’s indexed by Spotlight on my Mac.

From then on, when I’m working on a project, and I’m having trouble with something, or trying to remember something I might have seen, I open up that folder in Finder, and type the Class or Method names of the Classes I’m working with, and Spotlight will tell me the session names of the videos I might want to watch.

So, for example, if I type ‘NSFetchRequest’, the first result is “Session 214 – Core Data Best Practices” from WWDC2012. I type ‘registerNib:’, and I get “Session 125 – UITableView Changes, Tips, Tricks” from WWDC2011 (among others).

Then I just go to iTunes or the website, and I know which video to go watch.

It’s a handy trick (and I use it to search through all my eBooks on programming, as well), and when I’ve recommended specific videos to people, I’ve had several of them ask me how I keep the videos straight.

So hopefully it’s useful to some of you.

New Work in Progress - Million Words: Multiplayer Crossword Game for Parents and Kids That Grades on a Curve

Although I do iOS Contracting to pay my bills (at least to date), I hope one day to earn a living from my own apps, and, although it’s not ready for release, the time has come to unveil my new project.

GamePlay ExampleMillion Words is a turn-based crossword game where you’re scored not by what letters you managed to get into your word, but by the grade level of your word, relative to your age. This way my six-year-old daughter could play “HELLO” and I could play “HELICOPTER” and we would get the same number of points (more or less).

The Problem

When I got my retina iPad, my iPad 2 became my wife’s iPad, and my first generation iPad got freed up for my six-year-old (when I’m not using it to test how my code runs on old hardware). I erased the data and gave it to her so she could set it up as “hers”. Being six, she uses it primarily to play games, and I was frustrated to notice that those games fell into two categories:

*Educational Games, whose content she would exhaust in short order and lose interest in, and

*Fun, Endless games that she could play over and over, but that had limited educational value (think PopCap).So I started trying to think of what kind of game would keep her interest and teach her something, and thought that, like the console First Person Shooters, a multiplayer game might keep her interested, and I thought it would be fun to play a turn-based game with my daughter while I’m stuck at work. But I couldn’t find one, so I decided I’d make one.

My Attempted Solution

So a turn-based crossword game seemed a natural fit (remember, I want it to be educational, and spelling is a place she (and I think most kids in the SMS-generation) could use some practice). But the existing ones don’t work well for younger kids. First of all, they get crushed by the bigger words that parents can spell. Secondly, they get frustrated when they have a pile of letters that don’t spell a word (and don’t we all).

I licensed educational word lists from an American University for the content (American English only so far, but I might do UK/Australia as well if I can find a source). This also has the benefit of excluding those stupid 2-letter and 3-letter so-called “words” that people memorize just to play in word games and never use in conversation or composition.

So I decided the game would give you an adjusted score based on the grade-level of the word and your age. And I decided that (at least for kids) the game would make sure that there was at least one word at your level that could be spelled with the letters you were given (which can be done in a computer game, but not with letter tiles in a bag). That also makes it possible to make a “hint” system, so it can keep them from getting stuck (and maybe even teach them new words).

Board Became Too UnbalancedOf course, that creates a problem that I can’t end the game when the “bag of letters” is empty – because there isn’t one. So I came up with a different way: I’m hooking the letters to a Physics Engine and letting gravity end the game.

There are two cool things about this (aside from the visuals): First, if you intentionally play words that connect other words (which is an additional level of difficulty), then you can keep the board “stable” and play longer. Second, it enables an interesting “Solitaire” variant, where you are playing by yourself, just trying to see how large a board you can construct before it crashes. And, just maybe, it’s an interesting enough aspect that adults might like to play against each other, as well. Board Where Words Interlock

The possibilities

And there are lots of other things I have on the drawing board: letting parents put their children’s current spelling lists in the game, using the iOS5 dictionary to make “suggestions” when words are misspelled and to show the definitions of words.

And the most interesting possibility, I got from the name. My six-year-old told me I should call it “A Million Words” because it sounded cool to her. I told her the game didn’t have that many words in it, but she insisted. And, honestly, I haven’t thought of a name I like better (and I’ve tried, believe me). So I decided to take the other perspective and try to figure out what I could do to make the game fit the name. And what I decided was that I was going to track, on the website, the total number of words spelled by all the players of the game, and have a countdown to when A Million Words had been spelled, aggregate, in-game. And once that milestone was reached (as it hopefully will be), then the countdown would start being broken down by demographics: which age group would reach a Million Words spelled first: the kids or the adults? I think if I do that right, it could be an interesting marketing opportunity.

The future

VINES ThemeSo, obviously, I’m not done, yet. I hope to be done by the holidays this year, but we’ll see what happens. I still have a lot to do:

*Game balancing – getting the scoring right so different ages are competitive

*Monetization – I think now I want to make it Freemium and sell themed and power-ups like Temple Run, but I want to avoid the Smurfberry Fiasco

*In-game chat and Matchmaking – How do I allow that within a family, but don’t let strangers chat with your kids.And to get all that right, I’m going to need play testers of all different ages, and that means people have to know about the game. And I’m far more worried about the game launching to obscurity than the idea being stolen. So I decided to unveil the game and start talking about it.

TL;DR (In Conclusion)

I’m writing a crossword game where people of different educational levels can compete on a level playing field (so to speak). I’m hoping it will be done late this year, and I’m trying to validate that it’s the kind of game people might want to play. I hope that, if you’re interested, you’ll Sign up for the mailing list.

My Top 5 Factors for iOS Contracting Success

About a year ago now, I was contemplating leaving my day job and becoming an indie* iOS developer. My last day working in a cube farm was June 30th, 2011. Now, as I pack to leave for WWDC in the morning, it occurs to me how much my life has changed since I made that decision.

When examining my finances in preparation for this trip, I determined that in my first year as an indie I’ve made within $1000 of the amount of money I made in salary my last year as an employee, while spending more time with my family and enjoying my work so much more. Personally, I consider that to be a success.

Looking back, I can think of 5 things that I did that I think contributed most to that success, and I wanted to take this opportunity to share them with you all.

*5. Project FocusI think of my work (and speak with clients about my work) in terms of projects. I use traditional project management tools (often Gantt charts) to plan my work and track my progress, and I try to arrange for milestones to happen every week or two. That seems to help alleviate any concerns that my customers might have about doing business with a one-man shop. It’s helped me develop a “specialty” (if you can call it that) of cleaning up Apps that other bigger but lower-bidding developers (often acquired through Elance/oDesk) have made a mess out of.

*4. Books/VideosI read a lot, and I watch conference videos while I’m on a treadmill or rowing machine. I think that’s the biggest difference between me and many other developers whose work I often end up straightening out.

My favorite book this year was iOS Recipes by Paul Warren and Matt Drance, although I’ve read at least a dozen others.

My favorite video was the Core Data Performance series from Marcus Zarra, although the WWDC, NSConference and 360iDev videos were all very useful (and very cost-effective).

*3. ConferencesIf it weren’t for the 360|iDev conference in 2010, I would never have had the confidence to try to be an indie iOS developer (full disclosure: I’m Speaking at 360|iDev this September). I agonized over making my reservations for the September 2011 conference, because it meant I wasn’t getting paid while I was attending, but I’m so glad I did. I also went to 360|MacDev this February, MicroConf in April, and I’m about to leave for WWDC.

As I mentioned earlier, I buy and watch conference videos for many conferences, so you’d think that it wouldn’t be worth actually going to the conferences. I thought so, too, once, but I was wrong. What I get from conferences is networking, making (and renewing) contacts and topping up on the motivation that I need when things don’t seem to be going well.

*2. CocoaCoder/NSCoderNight/CocoaHeads/etc.Many major areas have meetups where iOS (and sometimes Mac) developers get together to work and learn and talk. I’ve been attending CocoaCoder Austin for a couple of years now, and I’ve been one of the organizers for about a year. Austin also has a South group SAiD, and a more entrepreneurial-focused group. These are great opportunities to learn, figure out what’s going on in your town. Check Meetup or ask around. If you can’t find one, start your own.

*1. Co-Working facilitiesBut I think the biggest factor in my success as an iOS contractor was my decision to spend time at a local co-working facility (mostly CoSpace, although I spend some time at Tech Ranch, where we have most of our CocoaCoder meetings, as well).

Co-working isn’t just a place to go to get out of the house and have some non-family human contact (although it does do that), but a good Co-working space facilitates introductions and a sense of community. Co-working became a source of contacts and contract opportunities for me, and I can safely say that, if it weren’t for some of the people I met while I was there, I would have completed this year having made far less money than I actually have.

Of course, your mileage may vary, but I hope this has been useful. It is possible to give up your day job and make the same money, while enjoying your work more and spending more time with your family – I know, because I did it. It hasn’t been perfect, and I’ve made my share of stupid mistakes, but I’m declaring victory on my first year as an Indie, and I’m going to go enjoy WWDC and look forward to my next year of making my own way in the world.

  • Some people may take issue with my characterization of myself as “indie.” Some people define indie as “Only works on your own stuff”, and that’s certainly not true of me (although I do work on some of my own projects). Personally, I choose to define indie as “Not sure month to month (or even day to day) when or how much you’re getting paid next.”

What I Learned During My Mac App Store Review

Two things happened on Thursday that made it obvious to me what I should write about this week. Mountain Lion was announced, and my first Mac App was approved for the Mac App Store.

Even though iDevBlogADay is about iOS programming, more and more of us are moving from iOS to the Mac. With the announcement that GameCenter will be coming to OS X, I’m guessing that more iOS developers might be thinking about coding for the Mac now than might have been last week.

So today I’m going to talk about my experience in getting my first App on the Mac App Store and specifically the differences in the approval process between the Mac App Store and the iOS App Store.

I wasn’t nearly as prepared as I thought

I first submitted my Mac App on October 17th, so it took me a day short of 4 months to get my App approved. That’s at least 3 times longer than I ever took to get any of my iOS apps approved. Partly because the MAS requirements are different, and part because I wasn’t paying enough attention. I learned a lot in the process, and I thought I would try to help other people avoid (at least some of) the mistakes I made. Hopefully this will help you avoid wasting both your time and the review team’s time.

Note: I’m only going to focus on the general interest stuff in this post. Since I wrote a developer tool whose primary purpose is to make things happen on a remote iOS device, it doesn’t fit into the expected behavior of a “normal” OS X App. So I’m going to ignore the issues I had that are specific to the type of App I wrote.

You can’t require 3rd-party Apps to be installed

My App uses Dropbox and Boxcar to “push” an iOS App build to all my test devices wirelessly. And my first rejection was because my app required third party products to be installed. That was a surprise to me, because I have used several iOS apps that require 3rd party services (how many iOS Apps have you seen that do nothing until you log in with Facebook Connect? – I’ve seen several).

So this required me to sit back and do a redesign (or sorts). Since I had built the entire App intending to rely on those services, I didn’t know what to do. So I added a new preference so that, instead of Dropbox and push notifications, you could use local Web Sharing and send an email to your device with the link to click to install your test App. It’s not nearly as useful as the Dropbox/Boxcar method, and I feel there should be a different solution, but I haven’t thought of a better way that could work inside the sandbox restrictions.

But the main thing is, my App is functional (even if in limited way) if you don’t have Dropbox and Boxcar, so it got me past that hurdle. (Personal aside: I use both Dropbox and Boxcar on an almost daily basis and if you don’t, and you have both a Mac and either an iPhone or iPad, I think you’re missing out on two of the most useful tools available to you).

The first rule of Sandbox is you don’t talk about Sandbox

Another rejection was because I had a description that said something like “To comply with Sandbox restrictions, if you use Dropbox, it must be installed in $HOME/Dropbox”. It seemed a reasonable thing to me at the time. In order to write to the Dropbox folder (with sandboxing enabled), I have to put the Dropbox folder path in the temporary exceptions part of my entitlements file. I understand why Apple doesn’t want us doing that – it means that, if they change their policy, then our descriptions would become inaccurate. Also, most users don’t understand such things, but hopefully all of mine do, since all this App’s users are iOS developers.

I had read the review guidelines, but I would not have thought this wouldn’t be okay. The rule that this violates is: “3.3 Apps with descriptions not relevant to the application content and functionality will be rejected”. So keep in mind that talking about internal Apple procedures might be considered “not relevant” and earn you a rejection.

Test on Macs with different configurations

I was also rejected because my App crashed if run on a Mac that didn’t have Xcode installed. The reason for that is beyond the scope of this post (and wouldn’t be relevant for most Apps), but it had never occurred to me to try to test my code on a machine without Xcode installed (all my Macs have Xcode – why wouldn’t they – it’s what I do all day). I uninstalled Xcode from one of my machines, and sure enough, I got the crash.

It was easy enough to fix the crash, but the important thing I learned was: I needed to have tested on configurations that were more generic than what I normally use.

They are serious about keeping the user informed

I was rejected for not including a progress bar.

Well, not explicitly – but there was a point while using my App when there was a pause, and no feedback was being provided to the user. Stuff was happening in the background, and I wasn’t blocking the UI thread or anything, but I wasn’t telling the user what the App was doing. It didn’t seem (to me at least) that it lasted that long, but they rejected it.

So I put a progress bar on it and, you know what, it greatly improved the user experience. I’m really glad I got rejected for that, because I like it much better now.

They are serious about User Experience

I also got rejected because I didn’t specify a minimum window size. Or at least, adding a minimum window size fixed the problem.

The rejection said that the user could resize the window so small that the app could no longer be used. They were correct – that window exists to be a drag-and-drop target, and if you make the window small enough, then you can’t drop your .app bundle onto it anymore. My initial reaction was “well, the user shouldn’t do that and still expect it to work”. But I was wrong.

The bottom line is that I hadn’t even considered what I wanted the App to do if the user resized the window – windows don’t get resized on mobile devices, so it hadn’t entered my thought process. After that rejection, I thought about what I wanted the App to do when a resize happened. And it’s a much better App for having thought that through.

So, in conclusion: It’s as much about design as code

I would say that, more than anything else, I learned that the difference between the User Experience on OS X and iOS is at least as great, if not greater, than the difference between writing code for OS X and iOS. When I was reading books and teaching myself about programming for the Mac, I tended to focus on the framework changes (e.g. NSView vs. UIView) and the new elements (NSMenu, NSDraggingDestination, NSTask, etc) and I mostly skimmed the design parts. That was a mistake.

Over the months, I got very frustrated with the review process. There were times I thought that I was never going to get the App approved. But even though people kept telling me that I should just withdraw it and sell it outside the App Store, I’m glad I didn’t give up. It’s a much better App than it would have been if I hadn’t done what it took to get it approved for the store.

WARNING: Blatant Self Promotion Ahead

Don’t say I didn’t warn you.

If you’ve read this far, and are an iOS developer, you might be interested in my new App, AppDropOTA. Which you can get for about the cost of the proverbial cup of Starbucks coffee here (App Store link).

After installing it, you configure it with your Boxcar email address and copy and paste a Dropbox Public folder URL into the Preferences panel. (Also, if you don’t have it, you should go install the Boxcar App and log in to it with your email address).

Now use Xcode to build an iOS App for the device, grab the .app bundle and drop it onto the AppDropOTA window. Your .app bundle will be turned into an .ipa file and placed into your Dropbox Public folder so it’s accessible via HTTP. Then you’ll get a push notification on the Boxcar app on your device(s). Launch Boxcar (via Notification Center is the quickest way), open the notification, and tap the “View Original” link on the item detail screen. You’ll get an alert pop-up prompting you to install your App. Click “Install” and you’re done.

When I’m testing, I do this several times a day. I have 9 iOS devices I test with: an iPad 2, an iPhone 4S and an iPhone 4 running 5.0, an iPod Touch running 5.1 beta, an iPad 1, an iPhone 4 and an iPod touch running 4.3 and an iPhone 3G and a iPod Touch running 4.2. (Soon, I hope to convince my customers to drop 4.x support, but haven’t, yet). I learned the hard way that I needed to test on different hardware when I shipped an App update for a customer that immediately crashed on all armv6 devices because of this Xcode bug. I wrote AppDropOTA to speed up the process of getting Apps on all my test devices.

Some people use TestFlight for this. For me, TestFlight is too public to use for every test build. I use TestFlight for builds I’m sharing with my customers, but I never push something to TestFlight until I’ve run it on my own device first. AppDropOTA is what I use for that (and it’s faster that TestFlight, too).

Hey, iOS Devs, Nice AppStore. Would Be a Shame if Something Were to Happen to It…

So, breaking iOS AppStore news this afternoon:  Path uploads your entire iPhone address book to its servers.

This sucks, and I’m pissed off, but not because my data is so precious, but because I’m scared of where this could end up.

Danger!!! Will Robinson! Danger!!!

Many of us in the iOS development community make our living off writing mobile apps.  Even more developers dream of one day being able to write apps as a profession.  One (probably overstated) estimate out this week says half a million jobs have been created. For those of us that can write code (or are wanting to learn).  Even if that number is inflated, this is still a great thing.

I just got back from the 360MacDev conference in Denver (a spin-off of the 360iDev conference I’ve attended and loved the last two years).  It was fantastic, and I had a great time.  There’s a great community of developers out there who are not just willing but genuinely happy to share what they know with anyone who will listen (although there is the occasional exception).

There’s exactly one reason why this is possible – because the ecosystem is still growing, and there are plenty of people who want to pay to get an App written, which is, of course, because Apps are generating a lot of money.

But all is not well.  As the app stores grow more crowded, people are cheating to try to stand out, and worse, users are discovering that their iPhones are tracking them everywhere they gotheir Android Phones are logging all their keystrokes, malware has invaded the Android market and even the iPhone isn’t safe from malware.

And when  the size of the market starts shrinking, then  everyone starts to panic, and before long  people don’t want to hire you and then  the knives come out.

There is one thing that we, as a development community, cannot afford – and that is for the people that download and use our software to be scared of that software.  Because then the need for apps starts to dry up, and the need for mobile programmers will start to drop.

Some of us are old enough that we remember trying to sell shareware on the PC back when viruses were rampant.  It was a tough sell.  And some of us remember how hard it was to sell mobile software (for PalmOS or Windows Mobile) in the pre-AppStore world.  Back then, it was a real undertaking just convincing a user that downloading any third-party program was worth their time.  We don’t want to go back to that.

This is the golden age of the indie developer (or at least the most golden age so far).  When else in history could   a single person make half a million dollars in a month, or   make a world-wide hit while commuting or   could 3 people beat a company with almost 1000x more employees?  It’s certainly not something I expected a “geek” to be able to do while I was growing up.

And for that to continue, we need our users to trust us, and the easiest and best way to do that is to be worthy of their trust.  There will alway be rogue actors and   assholes that try to scam users.  But those apps are short-lived (although not short enough), poorly reviewed, and there’s very little we can do about individual fraudsters, or users who don’t pay attention to which developer an app came from.

But when a respectable, well-written App like Path can’t be trusted, then we all have a problem.  The app is beautiful, obviously professionally designed and written, and well reviewed.  It didn’t need to be slimy to be successful.

And what we, as professional mobile app developers, of whatever flavor, need to take to heart, in my opinion, is this: Don’ t Be Scary .

If the professional, successful App Designers and Programmers agree to put what’s best for the ecosystem first, then companies will stop risking all of our long-term success, for a short-term advantage.

Yes, it’s less work to  store your users’ pictures unencrypted and unprotected on a server or  store plain-text passwords in your app, and if you want your app to be more popular, it’s tempting to harvest your users’ contact info, or jack up your App ranking,  but, even if you have a legitimate non-spammy reason for uploading your customers’ info, just don’t.  Please, please, please always err on the side of earning your users’ trust.  Yes, it might be more work for your current app, but remember, your current users are the potential users for all our apps, and whatever app you’re working on next.

And yes, some of us will piss off some people who want us to make apps for them by refusing to scare our users, but there will be other people who want us to build apps.

We will hopefully all be writing apps for years… Unless our users stop being our users.

Don’t forget that very few mobile apps are “necessary.”  They’re a luxury – and many (if not most) app purchases are quick impulse buys.  It probably won’t take much fear on the part of an individual user before he or she decides that, even if the App is worth 99 cents, it isn’t worth the risk that it might steal their data.

Then we all lose.

(Path Story link Via @mattgemmell.)

HTTP Testing to the Edge on iOS: the School of Hard Mocks

I’m a big fan of Automated Testing, even on iOS projects, but even when I was doing mostly Ruby, Java and C# work, I was never a big user of mock objects.

Now, I’ll admit that Mock objects can be useful under some circumstances, but I’ve seen them used too often in cases where a bunch of different developers each build their own little fiefdoms of their own code surrounded by Mock Objects where they interact with anything else. Each developer’s code runs perfectly when being tested against Mock input, but when you put all that code together, you can’t get a transaction working end-to-end, because the real world doesn’t obey the assumptions inherent in the Mocks.

So the Automated tests I write have more of a tendency to be more like what are called “Integration Tests”, even though I use “Unit Testing Frameworks” to write them.

When you combine that with the fact that I write a lot of iOS apps that talk to web servers, I want a way to test how my code talks to HTTP. And I want to know that my code handles things even when any library I happen to be using hands me errors to deal with.

When I first solved this problem years ago, we were using the Google Toolbox for Mac as our unit test framework, because SenTest didn’t work well back then. So, at the time, I built a solution based on GTM, but I went recently to try to recreate that solution for a new customer, and I realized that the files I had used had been deleted from GTM.

So I went spelunking back in the history of GTM, and pulled out the last version of the the files I needed before they were removed, and put them up on github in a new repository I’m calling SyntheticServerTest.

The way you use it is to look at the example test file.

You just have to run:

[testServer startServerWithDocumentRoot:]

With a document root directory that contains web content (I usually use ‘curl -O’ to pull known pages (either good or errors) from the server and write them to that directory), and have a mechanism so, that, while your test is running, the host part of the URL gets replaced with

@“localhost:%d”,[testServer port]

and the test HTTP server, running in the background (in the simulator or on the device), will get the HTTP request and hand you back the test data file in response.

This way, you can test your App’s entire HTTP stack, including any parsing libraries you may be using, with both real data (that doesn’t require you to be on line) and with bad data, to make sure you are correctly handling whatever errors your parsing or network library is throwing off.

Using Regular Expressions Part 2 - the Cocoa Connection

Last time, in Part 1 of this series, I wrote about the basics of regular expressions, and the phrases I tend to use. Today, I’m going to talk about the mechanics of how I use Regular Expressions in Cocoa.

But first, an historical diversion

In my opinion there are, two different ways that programming languages implement Regular Expressions: The perl/ruby way, and the Java/C#/Python/Cocoa way.

In ruby and perl, regexes are implemented directly on the String type, whereas in the other languages, there a separate object that contains the functionality. Here’s what you need to know to do a regex substitution on a string in ruby:

myString.sub(‘pattern’,‘replacement’)

clean, easy, and immediately useable if you know what pattern you want to use.

Here’s what you need to know to do the same thing in Cocoa:

+[NSRegularExpression regularExpressionWithPattern:(NSString *) pattern

options:(NSRegularExpressionOptions)options error:(NSError **) error]

–[NSRegularExpression replaceMatchesInString:(NSMutableString *) string

options:(NSMatchingOptions)options range:(NSRange)range 
withTemplate:(NSString *)template]

which is not clean, not easy and contains a bunch of stuff you have to go look up to be able to get started. What are NSRegularExpressionOptions and

NSMatchingOptions? What’s a template? Do I really have to create an

NSRange for this? And that leads to the obvious question: Is all this effort really worth it?

Now I don’t know about you, but I don’t want to spend any effort remembering any of those option parameters, and I don’t want to take the time to look them up any time I want to use a regular expression. To me, the beauty of Objective-C is that it gives us the ability to build most of what you need to know directly into the method signatures.

Let’s simplify things a little

So that’s what I did. For the rest of this post, I’ll be using the categories on NSString found in a repo I wrote on github called RegexOnNString.

There are three basic methods I wrote:

–(NSString ) [NSString stringByReplacingRegexPattern:(NSString )regex

withString:(NSString *) replacement]

which takes a string, finds the occurrences of the regex pattern and replaces them with the string replacement.

–(NSArray ) [NSString stringsByExtractingGroupsUsingRegexPattern:(NSString )regex]

which gives you an array of all the pattern groups (things in parentheses) it found in your string, and

–(BOOL) [NSString matchesPatternRegexPattern:(NSString *)regex]

which just tells you whether a pattern is present in your string or not.

There are two additional, optional parameters that you can add,

caseInsensitive:(BOOL) ignoreCase and treatAsOneLine:(BOOL) assumeMultiLine.

caseInsensitive is hopefully self explanatory, and treatAsOneLine just means that you expect that your string has (or might have) newline ( \n) characters in it, and you want them to be treated like any other character.

To get them, you just need to grab the MIT-licensed code from github, include NSString+PDRegex.h and NSString+PDRegex.m in your project, and put

import “NSString+PDRegex.h”

in the top of your source file.

How about some examples?

The simplest of these is the one that returns the boolean, like so:

if(![emailAddress matchesPatternRegexPattern:@“@.\..”]) {

NSLog(@"If the user is going to give us a fake email address" \
      @" they could at least try and make it look like one" \
      @" by making sure it has an at-sign and a dot in it.");

}

I use this a lot for string validation. No sense in trying to send an email if there isn’t an at-sign in it, and no use trying to convert an NSString to an NSURL if the string doesn’t at least contain ‘ ://’. (Note that I have to use two backslashes there because a @“@.*.” will cause Xcode to generate a: Lexical or Preprocessor Issue: Unknown escape sequence ‘.’ warning).

The one I use next most often is the one that returns an NSString. I use this one for extracting substrings. For example, in:

<Warning: Shamless Plug> a Mac application I recently released as an Open Beta that helps iOS developers deploy Apps to their test devices without having to use a USB cable

I’m getting a string that is the path of the .app file that the user dragged-and-dropped onto my App (and it’s either a path if they dropped it onto the App Icon in the Dock, or a URL if they dropped it onto the Window). From that string, I need to figure out what their iOS App is named (so I can use that name in the notification). I use the stringByReplacingRegexPattern method for that. I could use [[NSString lastPathComponent] stringByDeletingPathExtension] for that, but by using regexes, I don’t have to go look up the path component methods, like I just did to put them in this post. But an even better example from that app is:

NSString *dSYMPath = [droppedPath stringByReplacingRegexPattern:@“\.app$” withString:@“.dSYM”];

So that I can save off the dSYMs so that the user can get to the symbol data for that build if they need it later.

I also use it so that, in order for my App to get the user’s Dropbox’s public URL, I can let the user drop any Public URL that Dropbox gives them into the preferences panel, and I can use:

NSString *dbPublicRoot=[pastedLink stringByReplacingRegexPattern:

@"^(http://dl.dropbox.com/u/[0-9][0-9]*)[^0-9]*.*$" withString:@"$1" caseInsensitive:NO];

so that I don’t have to rely on the user to correctly truncate the URL at the right place, and the user doesn’t have to think about it.

The last method, the one that returns the NSArray, I don’t use as often, but when I do, it can save me a lot of effort. For example, recently I was implementing a Tic-Tac-Toe game as a programming exercise as part of an interview process. So when I was shipping turns between the two players, I was actually sending one string:

NSString *stringForThisMove = [NSString stringWithFormat:

  @"Move %@=Player %@ to Square %@\n",
  [move TurnNumber],
  playerThatMoved,
  [move SquarePlayed]];

and then on the receiving end, I used:

NSArray *extractedStrings=[moveString

   stringsByExtractingGroupsUsingRegexPattern:
   @" *^Move  *([0-9]) *= *Player  *([X|O])  *to  *Square  *([0-9]) *$"
   caseInsensitive:YES treatAsOneLine:YES];

from which [extractedStrings objectAtIndex:0] was the move number, [extractedStrings objectAtIndex:1] was the player (@“X” or @“O”) and [extractedStrings objectAtIndex:2] was the number of the square they moved to (where the first row of the board was 1-2-3 and the last row was 7-8-9).

Now, there are many other ways I could have encoded that, but the nice thing about using strings for it was that anyone looking at the intermediate value (in the debugger or logs) could easily tell what move was being talked about at that point, and if I were ever to need to come back to this code later, @“Move 1=Player X to Square 1” will make sense to me (after all, that kind of notation has been of use in the Chess world for hundreds, if not thousands of years).

But aren’t Regular Expressions slower?

Well, define slow :–).

In the test suite for my RegexOnNString category, I have a test that does 1000 string replaces:

for (uint i=0; i< 1000; i++) {

if (lastTimeString) {
    NSString *currentNumberString=[NSString stringWithFormat:@"%u",i];
    NSString *replacementString=[lastTimeString stringByReplacingRegexPattern:@"[0-9][0-9]*" withString:currentNumberString caseInsensitive:NO];
    STAssertEqualObjects(replacementString, currentNumberString, @"regex replace failed");
}
lastTimeString=[NSString stringWithFormat:@"%u",i];
i++;

}

Now each of those regex’s is different (by design), so I can’t compile them, and I’m creating and throwing away my NSRegularExpression object and a temporary NSString every run. So it’s near a worst-case scenario. By way of comparison, I do another loop of 1000 replaces, using [NSString stringByReplacingOccurrencesOfString: withString:] to see how much slower the regex makes the task.

The output from running the test on my 4thGen iPod touch is:

2011-10-15 17:23:00.748 RegexOnNSStringIOSExample[224:607] 1000 regex replaces took 0.167364 seconds 2011-10-15 17:23:00.776 RegexOnNSStringIOSExample[224:607] 1000 String replaces took 0.025167 seconds 2011-10-15 17:23:00.777 RegexOnNSStringIOSExample[224:607] Simple String substitution 6.650140 times faster

and on my daughter’s 2nd Gen iPod touch, the output is:

2011-10-15 17:33:37.631 RegexOnNSStringIOSExample[183:307] 1000 regex replaces took 0.641442 seconds 2011-10-15 17:33:37.756 RegexOnNSStringIOSExample[183:307] 1000 String replaces took 0.119230 seconds 2011-10-15 17:33:37.768 RegexOnNSStringIOSExample[183:307] Simple String substitution 5.379869 times faster

So yes, it’s slower. It takes 0.17 milliseconds on a 4th-gen touch and 0.64 milliseconds on a 2nd-gen touch. And it’s between 5 and 7 times slower than stringByReplacingOccurrencesOfString:withString. If 0.52 ms really matters in your code when running on a 2nd-gen touch, then you should use stringByReplacingOccurrencesOfString:withString instead.

So, in conclusion,

I hope you found this post useful. If you need to do string manipulation, Regular Expressions are a time-tested way to do that, and I hope the extra methods I’ve talked about here will simplify things if you want to do string manipulation in your Cocoa code.