I <3 Xcode 5 and AppleDocs

If you are an Objective-C developer, rejoice!  You can now have AppleDoc-style documents built right in to your project with Xcode 5!  All you need to do is add special comments in your headers and Xcode will automagically suck those comments right into its docs!

For example, if I format my function declaration like so:

/**
 A cool method to do some nifty stuff!
 @param foo a useful parameter
 @param bar another useful parameter
 @return the result of mashing foo and bar together
*/
- (id)niftyMethodWithFoo: (Foo *) foo andBar: (Bar *) bar;

Then when I option-click on that method name from anywhere in my source code I get a quick view of the help:

quickdocs

Our friends at NSHipster have a great article on how to format your comments to generate awesome AppleDocs, so I won’t bore you with that here.  There is a lot more you can do that just document functions, so I encourage you to read all about it and start adding AppleDoc comments to your code!

Apple Gives Some Love to Older Devices

As an iOS developer dealing with old devices is a thorny problem. Progress in iOS marches ever onward and eventually a new version comes out which drops support for older devices. You are then faced with a choice: keep supporting that older OS and your established customers who are unable to upgrade, or abandon them.

Apple has come up with a new feature for users on older versions of iOS which allows them to download the last compatible version of your app.  This is good news for users and potentially a headache for developers.

I always try to support the older OS as long as possible. If there’s a new OS feature I’d like to take advantage of it’s usually possible to do so–and make it so that feature is simply unavailable for users on an older OS version. But at some point there is a fundamental new feature you want to support that requires an architecture change to your code and means dropping that old OS.

When it does finally come time to abandon support for an OS version I always try to make sure there is one final version of my app that has a number of bug fixes and improvements that will leave these people happy until such time as they get a new device that can support the latest OS.  This version of the app goes up in the app store and in the “What’s New” metadata I’ll highlight that the update is the last version to support whichever OS version is being dropped.  I’ll leave this version in place for several weeks to a month–which should be ample time for my users to update.

Still, some stragglers who are lazy about updating their device might not get around to it, or some new customer with an older device might hear about my app and want to try it.  Apple’s new system is going to help them out by letting them download and use my app.  Hooray!  This is good news for them and for me.

The one main gotcha is if that last version is a doozy–perhaps because of some nasty bugs I never got around to fixing.  Undoubtedly there will be developers in this camp and some people who are unhappy with Apple’s latest move.  I think this just highlights the importance of doing that final maintenance release before you drop support for an OS.

Update 9/20/13

Kyle Richter (co-founder of Empirical Development) points out some additional considerations with Apple’s new service.  I agree there are some pitfalls, but on balance I still think this is a win for users–as long as developers are careful to put out a high-quality final version before dropping support for an older OS version.

OCMock Update

The website for OCMock, a framework dear to my heart, has received a big facelift! It’s much cleaner and easier to use than ever.  They now publish their GitHub link on the download page–which makes installation a snap if you’re using Git.

If you like including third-party frameworks in your apps it is so easy with Git submodules.   e.g.:

cd path/to/my-git-repo
git submodule add git@github.com:erikdoe/ocmock.git
git commit -a -m "added ocmock submodule"

Now you’re ready to integrate the third party source into your project. Refer to the installation instructions for that source (eg: OCMock iOS installation).

If this is too much to swallow, you can always try CocoaPods. I’m not a fan because it requires mucking with Xcode workspace files–and I think it is more difficult to configure to use private repositories.  I find submodules easier to use with build servers, as it works out of the box. CocoaPods requires installing and configuring another tool.

Anyhow, go install the third party framework, commit your project changes and start coding!

Also, if you need to clone your repository you’ll need to initialize the submodules afterward. Git doesn’t automatically go out and fetch the submodules during a clone operation.

git clone me@github.com:me/my-git-repo
cd my-git-repo
git submodule init           <-- initialize submodules
git submodule update         <-- make sure they're checked out

Lastly, if you need more info about git submodules there’s lot of info on the interwebz.

Check Your Error Param!

This is a pretty elementary topic, but one of the most common problems I see on StackOverflow goes like this:

user12345: My code doesn’t work and I don’t know why!  It looks like this:

id result = [NSSomeFoundationClass getSomeData:@"some input" options:0 error:nil];
if (result == nil) {
    NSLog(@"WTF? Where's my data?!");
}

These posts get quickly down-voted and a backlog of comments that tend towards the shaming side forms. So please, new iOS and OS X developers, if there is an (NSError *) error parameter for the function you’re calling, for the love of all that is good, check this value! Nine times out of ten it will tell you exactly why the call is failing, eg:

NSError * error = nil;
id result = [NSSomeFoundationClass getSomeData:@"some input" options:0 error:&error];
if (result == nil) {
    NSLog(@"Oops, getSomeData failed with error: %@ (userInfo: %@)", [error localizedDescription], [error userInfo]);
}

If you’re lucky, a helpful message like this one will appear in the console:

Oops, getSomeData failed with error: You passed an invalid parameter! (userInfo: { NSProTip = "Go read the docs to understand what this error means and how to fix your code!" })

And if the foundation method you’re calling doesn’t have an error param, double check the docs. Many methods have an overloaded version which takes more options and provides an error param. Use these methods instead to gain more control over how the method functions, and learn about why it may fail. For example, NSData has several such methods:

+ (id)dataWithContentsOfURL:(NSURL *)url;
+ (id)dataWithContentsOfURL:(NSURL *)url options:(NSDataReadingOptions)readOptionsMask error:(NSError **)errorPtr;
+ (id)dataWithContentsOfFile:(NSString *)path;
+ (id)dataWithContentsOfFile:(NSString *)path options:(NSDataReadingOptions)readOptionsMask error:(NSError **)errorPtr;

Along these same lines, often when your app crashes the OS will throw an exception. This, like an NSError, will give you a clue as to what’s wrong. If you go into the debugger and set an exception breakpoint, then the debugger will even halt where the exception is thrown–which is very helpful for tracking down the problem in your code.

Buddha’s Hand & Tonic

Recently Jenny and I visited Oakland and went to the wonderful St. George’s Spirits in Alameda (makers of Hangar One vodka, among other things).  They are located in a hangar on an abandoned naval base and they have a wonderful tasting room and tour.  We ended up buying a number of spirits from them–absinthe, gin, Williams pear brandy, whiskey and the most amazing citron vodka I’ve ever tasted.

The Hangar One “Buddha’s Hand Citron” is phenomenal.  I highly recommend picking some up if you are in the market for some citron vodka.  In case you’re unfamiliar, Buddha’s Hand is an asian fruit that looks like a freaky alien–or hand of a very enlightened dude.  It has a wonderful citrus flavor and the geniuses at St. George’s brilliantly decided to use it in their vodka.  It makes for the best citron vodka I’ve ever had. Theirs isn’t too sweet, too sour or too syrupy.  It’s just right.

The first drink I made with the Buddha’s Hand wasn’t too exciting, but it was refreshing and delicious.  I made a classic Gin & Tonic, with a splash of citron.

A Gin & Tonic made with Hangar One Buddha's Hand Citron

A Gin & Tonic made with Hangar One Buddha’s Hand Citron

Fill a glass with ice, add two ounces gin, one ounce Hangar One Buddha’s Hand Citron and top with tonic water (about three ounces).  Squeeze in some fresh lime to taste.  Enjoy this refreshing beverage on a patio in the sun.

 

Treat Compiler Warnings as Errors

I’m a big believer in the compiler option to treat warnings as errors.  Compiler warnings are our first line of defense against inadvertent screw-ups in our code.  It means you’re probably doing something wrong, or that goes against recommended practices.  ie: “Sure, technically you can do this but it might result in unexpected behavior, memory leaks or other problems if you’re not careful.”  So turn on “warnings as errors” to prevent accidents.

The warning may just be a “head’s up”–like an unused variable warning.  Maybe you forgot to use it somewhere in your code.  Maybe you did some refactoring and no longer needed it.  In this case just fix your code.

There may be cases where you understand better than the compiler what you’re trying to do, and you do want to exploit a capability of the compiler to do something you think is really clever.  (We programmers do like to be clever, don’t we?)   Chances are you’re wrong though and you should probably find a different way.  The next version of the compiler might be more strict–or worse, might behave in a different fashion in this case and cause a change in your code’s behavior, often for the worse.  If you want maintainable code, treat the compiler’s warnings seriously.

However, if you are absolutely certain you know what you need to do and there’s no alternate way to accomplish your code, then don’t turn off the “warnings as errors” build setting, and don’t turn off the warning globally.  Just turn it off for your one risky piece of code and document it.  eg:

#pragma clang diagnostic push
// Turn off the "undeclared selector" warning because we're
// checking to make sure that the target responds to that 
// selector before trying to perform it.
#pragma clang diagnostic ignored "-Wno-undeclared-selector"

if ([target respondsToSelector:@selector(doSomethingCool)]) {
    [target performSelector:@selector(doSomethingCool)];
}

#pragma clang diagnostic pop

Notice that while I’m exploiting this ambiguous compiler behavior I’m also being careful to avoid misusing it!

Finally, there may be a situation where third party code has some warnings. One option would be to fix the warnings and submit a pull request to the owner. This might not always be feasible though (or you simply don’t have time to fix someone else’s code). You can also turn the offending warning(s) off on a per-file basis. This is nice because the configuration change goes into your project settings, not the third party source. This could help avoid merge conflicts or having to re-apply your changes when updating the third party source to a newer version.

In Xcode select your target and go to the “build phases” tab. Search for the name of the offending file and double-click on the “compiler flags” field (to the right of the file name). Enter the flag to disable the offending warning, eg: -Wno-undeclared-selector.

Disabling a compiler warning on a per-file bases.

Disabling a compiler warning on a per-file bases.

Lastly, it’s not always easy to know what the name of the compiler flag is for the warning you disable. Your compiler should have documentation about this, as do the Internets. Try searching for the error message and “disable”. It’s very likely someone else has had this problem and already found the compiler flag for you. And if you don’t get any results it may be a sign that you’re doing something inadvisable.

$27k for Kids

I recently participated in Treehouse’s FORE! Foster Kids Mini Golf Tournament 2013. Check out the pics on Facebook.  My team (the Teetotalers) raised almost $1800 to help foster kids.  The event as a whole raised $27,486! Not only that, but it was a lot of fun! Free refreshments from Ninkasi, Chateau St. Michelle, and Dick’s (nothing like wine and fast food cheeseburgers). If you enjoy mini golf, good wine and beer (and Dick’s burgers) then definitely join in the fun next year!

A special thanks to everyone who donated to my team and I!

Thread This!

Today I wrote a utility to ease the use of dispatch queues and GCD (Grand Central Dispatch) in Objective-C.  GCD is very powerful, but it’s written in C and I often find there’s a lot of boilerplate code required in order to use it.  So I wrote a light wrapper called NHThreadThis which makes it a bit easier.  Of course the provided source code has unit tests and a sample app.

@todo: dispatch I/O and sources API support!