Awesome LLDB Trick

Ever get tired of trying to inspect CGRect values in LLDB?

(lldb) po self.view.bounds
error: property 'bounds' not found on object of type 'UIView *'
error: 1 errors parsing expression

I know, so annoying, right? Fortunately Craig Hockenberry has found a great trick in Xcode to make inspecting UIKit structures easier.

(lldb) expr @import UIKit
(lldb) po self.view.bounds
(origin = (x = 0, y = 0), size = (width = 375, height = 667))
(origin = (x = 0, y = 0), size = (width = 375, height = 667))

Read his article for all the details.

CocoaPods > Git Submodules

I must take a moment to recant some comments I made over a year ago about CocoaPods in a post about OCMock.  The first time I came across CocoaPods I thought it was pretty awesome, but then reality set in.  I had problems getting my project configured.  It would sometimes crash with cryptic errors (and still does if you have syntax issues).  I had trouble getting it to work with our continuous integration system.  Then a developer I have much respect for told me to just use Git submodules–it does what CocoaPods tries to do the “right way” I was informed.

Fast forward a year and I have changed my tune.  Git submodules is a reasonable solution to the problem of integrating other projects–but that’s not the primary problem that CocoaPods solves.  The real power of CocoaPods is having a searchable repository of open source frameworks at your fingertips.  In addition, with Git submodules there is usually a messy bit of configuration to do in order to get the framework integrated–and if you decide you don’t want to use it, additionally messy work to remove it.

CocoaPods makes it simple to find and include thousands of open source frameworks into your project.  It does the heavy lifting of dealing with dependencies and integrating into your project.  It works with Xcode’s Bots and Jenkins.  You can even configure it to use a private repository which contains your own frameworks that are not to be distributed to the public.

What’s even cooler? It makes it drop-dead simple to create and distribute a framework for iOS or Mac.

The only thing you need to do is evaluate the quality of the code you’re using.  There’s a lot of stuff out there and not all of it is great.  Buyer beware (the linked article is about Ruby Gems, but applies to all open source code).


Testing Your Software: Or How To Make Changes With Confidence

Writing unit tests is important.  Without unit tests, how do you know that your software still works when someone makes a change?  Sure, you can deploy a small army of manual testers to double-check that it still “works.”  But maybe the change you made has subtle effects in disparate parts of your code–are your testers going to cover everything?

The best way to have confidence that your code is functioning properly is to build and maintain a suite of unit tests.  There are entire books written about this topic (for iOS developers I like Test-Drive iOS Development by Graham Lee), but the most recent issue of covers just this very topic and is a great place to start if you’ve never written tests in Objective C.


Top 10 CoreData Tools

Matthew Morey on the Ray Wenderlich website has written a great post on his top 10 CoreData tools to help make one’s life easier. I’ve written a bunch of code to manage CoreData stacks, make fetch requests, ingest JSON in to CoreData and serialize back into JSON… some of these tools are a big time saver.

One thing I would note though: the author’s own framework (MDMCoreData) looks helpful–but I wouldn’t initialize it on the main thread, as it could take a long time if there is a migration required. You wouldn’t want your app to become unresponsive and get killed with everyone’s favorite 0x8badf00d

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:


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 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
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.