Archive for the 'Software Development' Category

You Got Your License In My Keychain!

The One In Which Paul Talks Out His Hat (metaphorically, since he and hats don’t get along).

During an entertaining aside in Andy Ihnatko‘s keynote at this weekend’s Voices That Matter conference, I was reminded of a thought I’d had a while ago: Why don’t Mac desktop applications store their license info in the Keychain?

Complaining about restoring license keys should be just as trite of a humor topic as little bags of peanuts on flights, but it still holds true. Go to restore a machine, or move to a new one with a clean install, and you can write off at least an afternoon launching and entering at least two text fields per application.

Maybe I’m the only one who feels quite comfortable with syncing to MobileMe–I actually consider it the feature that keeps me coming back. (I do know there are people who have frustrating issues, and I truly feel for them, but I continue to believe they are in the minority.) Given that setup, here’s how I’d see setting up a new laptop:

  1. Configure my MobileMe account and sync down the data, setting up my Mail accounts, Address Book and Calendar–and Keychain.
  2. Launch a new copy of my licensed application.
  3. There is no Step Three. Go on your merry way.

I’m not expert enough to suggest that it would improve security of your key, but it sure would discourage casual tweaking more than the plist or hidden file schemes you’d need to develop on your own. Also, separation of license key from a preferences file (hopefully developers are already doing this) allows a user to delete the preferences and start fresh without having to worry about relicensing.

I understand that Keychain development can be convoluted, but is that reason enough to not make the user’s life a little bit easier and your support burden of finding a lost license a little less frequent?

As I said at the top, I realize I’m talking out of my…hat here. I don’t have experience doing this (yet), so I am interested in hearing reasoned arguments. Until and unless this is proven untenable, simply consider it a feature request for your next release.

Bughunting a Bashful Table View

I ran down a strange bug yesterday that I thought I would recount in the hopes of saving someone else the half day of frustration.

I was going along, minding my own business, implementing a typical -tableView:didSelectRowAtIndexPath: delegate method to create a view controller, push it onto the navigation stack, and then…nothing. The view didn’t appear, and the app interface became unresponsive. Numerous pauses in the debugger showed what would appear to be normal stacks in the running of the app–no infinite recursion going on, thankfully.

The view was actually in a strange nesting of UITableViewControllers, UINavigationControllers and UITabBarControllers, so I reworked that to the bare bones of a UITableViewController pushing a freshly made UITableViewController onto its navigationController. I verified that it was being initialized properly, and that I had a valid navigationController to push onto (and other view controllers did push with the same navigationController). Still no change.

(Read the article)

Sudden Termination

Today, Tim Bray commented about Android applications needing to frequently save their restore state and be ready and able to gracefully terminate without notice. (This behavior also applies to iOS apps, of which I have much more experience than Android.)

At some point, after I’d explained a few times why you have to write software this way on Android, I started wondering why all software, without exception, isn’t written this way by default.

As of 10.6, Apple added enableSuddenTermination and disableSuddenTermination calls to the NSProcessInfo API to allow you to implement similar behavior on the desktop. At its most simplistic description, you can inform the system your application doesn’t need to have its memory paged back in just to destroy it all–just kill the process and you will be sure it behaves properly on relaunch.

I encourage all fellow iOS developers who have already acquired a “sudden termination” design style to make note of this when developing a desktop Cocoa application; I also encourage desktop Cocoa developers to start thinking about how they would design with this paradigm, as it will be one more portable technique when and if you decide to go mobile.

(NSCache and Purgeable Memory is another new-to-10.6 mechanism I consider similar to iOS’ didReceiveMemoryWarning, only giving the OS permission to purge memory instead of it requesting you clean up.)

My Accessorizer Configuration

Due to “overwhelming demand,” I am sharing my configuration set for Accessorizer here. I think there needs to be some explanation to many of the decisions, though, so here you go. This is not intended to be an interminable discussion of coding style and practices, though–if you disagree, go ahead and make your own configuration based on mine. This is also not intended as comprehensive documentation for Accessorizer–read its included documentation, explore tooltips, and experiment freely.

(Read the article)

Accessorizer 2.0 Configuration Sets

The new version of Accessorizer is out! I’m still amazed at how many Cocoa (including iPhoneOS) developers I encounter who don’t know of this awesome utility. Here are just a few things this app does:

  1. As its name suggests, it will generate the getters and setters for ivars you point it at. It will do this using Objective-C 2.0 @property syntax if you specify it. (I use the 2.0 syntax and revert when I want to customize a getter or setter so i can start with a “standard” usage style.)
  2. Automatically recognize UIKit and AppKit classes and mark the properties as IBOutlets.
  3. Recognize non-object ivars and set their properties as “assign” instead of “retain”.
  4. You can configure defaults for ivar classes (all my NSString and NSData properties default to “copy” instead of “retain”).
  5. Generate all the methods for collections to be nicely Key-Value Observing compliant.
  6. Generate Keyed Archiving and Unarchiving methods for your ivars.
  7. Generate template code for a Singleton class.

That’s really just scratching the surface, but it’s the main functionality I use. As a Cocoa developer, you truly do owe it to yourself to check it out.

What makes me (rather selfishly) consider 2.0 an awesome update, though, is a feature I requested: Configuration Sets. The request grew partly out of encountering co-workers at contracting gigs who didn’t use Accessorizer. There are so many items to customize in the application, a first use could be daunting. If I can say, “Here’s my configuration to get you started,” and pass along my exported Configuration, they’re more likely to use it. (It also helps that they can now feel confident that they can revert after experimenting with settings.)

If I’m working on multiple projects with multiple clients, I can save their specific formatting requirements and switch between Configuration Sets when I change between projects.

If your company has defined formatting standards for the aspects Accessorizer can generate, standardizing with a Configuration Set allows you to quickly bring a new team member up to speed and into compliance.

There are more aspects to Configuration Sets I’d like to see, but they fall on the “magical” end of the spectrum; Kevin has done a great job of implementing the (more than) 80% part of it.

Seriously: Why aren’t you using Accessorizer?

 

Clean Up Your Actions

We all know how to define an IBAction:

- (IBAction) sliderChanged:(id)sender;

For the iPhone, you can even define it without the sender if the method won’t use it:

- (IBAction) sliderChanged;

The annoyance comes when implementing the method–that generic id parameter needs to be cast to the class you usually already know it to be, resulting in either casts all over:

- (IBAction) sliderChanged:(id)sender {
   int progressAsInt = (int)([(UISlider*)sender value] + 0.5f);
   float minValue = [(UISlider*)sender minimumValue];
   float maxValue = [(UISlider*)sender maximumValue];
}

or the use of a local variable whose sole purpose is to hold the pre-cast parameter:

- (IBAction) sliderChanged:(id)sender {
   UISlider* slider = (UISlider*)sender;
   int progressAsInt = (int)([slider value] + 0.5f);
   float minValue = [slider minimumValue];
   float maxValue = [slider maximumValue];
}

Clean it up

The key to cleaning up your IBActions lies in Objective-C’s behavior of treating all objects as id at heart: Declaring a type for an object is really only beneficial to you at compilation time, warning you of possible mistyping. (It also enables autocompletion.) But that’s not a limitation, it’s something to leverage!

When you know the single class (or superclass of the family of classes), declare it in the method signature:

- (IBAction) sliderChanged:(UISlider*)slider {
   int progressAsInt = (int)([slider value] + 0.5f);
   float minValue = [slider minimumValue];
   float maxValue = [slider maximumValue];
}

If you’re one of those (crazy) people who call the action method in code, you will now be warned when trying to pass an unexpected control (e.g. a UISwitch instead of UISlider).

Added bonus: By declaring the action with a specific parameter type in the header, Interface Builder will use that information to filter available connections. Not only will you have a shorter list of actions to choose from when connecting, you won’t even be allowed to accidentally connect a UISwitch to an action expecting a UISlider.

Note: If you do clean up actions in this way for existing projects, verify your nibs afterward. Interface Builder will display a warning icon in the lower right corner of the nib window, but the CompileXIB build phase is not configured to generate these warnings by default.

Practical XML Parsing

I presented “Practical XML Parsing” at the September 10, 2009 meeting of Seattle Xcoders. While there is still a touch of the initially intended distaste for parsing XML with DOM, it evolved into more of an overview and brief introduction of NSXMLDocument and NSXMLParser.

After cleaning out large copyrighted material (part of a Justin Timberlake song on the title screen and a Star Wars snippet on the XQuery screen) and removing many of the Keynote build animations I like to use but which translate poorly to static images, I have made the presentation available. I didn’t record the audio, so the text may seem more terse than it really was.

  • HTML export with most of the animations still intact
  • Zipped archive containing:
    • Keynote 09 file
    • PDF export
    • XMLDemo source serving as the examples I showed

Software Illusionist

The only time I ever attended MacWorld Expo, I was working behind the booth for a Mac retailer in the Bay Area. It was a long and tiresome time, without the opportunity to explore the other booths. (I believe RAMDoubler might have been the show hit, to give you a Dark Ages reference point.)

Even behind the booth, I got to meet a lot of interesting people. There were plenty of independent developers even then, and many of them had whimsical titles on their business cards; I seem to recall a “Grand Poobah,” but the one title that made the biggest impression on me was “Software Illusionist.”

I remarked on the title and the gentlemen replied to the effect of, “really, that’s all it is I do–present an illusion that people find useful.” That simple statement (probably mutated somewhat through the years in my memory) was revelatory for me.

It may seem trite to say “it’s all ones and zeroes” but at some level that is all we do as developers: Find ways to organize and present data patterns to users in a manner which doesn’t require a Beautiful Mind to interpret, or make it look like a ball bouncing around an artificial rectangular constraint on screen, or make it sound like music, or convert physical stimuli to a data pattern to present later. When the user buys into the illusion and doesn’t have to hear the creaking of the mechanism, the Software Illusionist has succeeded.

To that Software Illusionist, whoever you were (or hopefully still are): Because of you, to this day I am still compelled to make my software feel like magic. Sometimes it feels like a curse, but I still consider it a blessing.

Thank you.

Happy Birthday

They say the best gifts are handmade. For my wife’s birthday last year, I came up with the idea to write a simple little “birthday card” application and slip it on her iPhone to surprise her. I scanned in some graphics from a real birthday card and digitally chopped it up and added some animation to give it that true “Made in Flash” feel, and stayed up until 1 AM working to get ad hoc provisioning working on her phone. I even had it register a protocol handler so I could send her an email while she was at work saying “click this link: <happy://birthday> from your iPhone email” and it would launch the application. It was a hit.

The one thing I had planned but couldn’t get working was for the appliction to play a song. Core Animation took enough of my brainpower at the time, and the idea of learning AudioUnit in such a short time was quickly dismissed–I would have to “ship” without that feature. But a recent post by Mobile Orchard’s Dan Grigsby showing the simplicity of AVAudioPlayer prompted me to pull the code off the shelf and give it an update.

What a dusty shelf that was. The project was configured for SDK 2.1(!) and some of the code was indicative of “tweaking until it works.” As I was updating the project for 3.0, moving code to Interface Builder and swapping lots of Core Animation code for UIView animations, it dawned on me that this has surprisingly many little tidbits of code and would be good to share.

(Read the article)

iPhone Development Course

Local Xcoders founder Joe Heck has just announced his 2-day iPhone course/workshop here in Seattle.

Joe has a very solid grip on the topic, and a seemingly boundless desire to both share what he’s learned and learn from others. Writing for the iPhone can be a bit disorienting at first, especially if you’re not already familiar with Cocoa; Joe is an ideal sounding board for questions you may worry might mark you as a “rookie.”

We got a preview of the course at last month’s Xcoders meeting, and I highly recommend it for anyone wanting to get up to speed on iPhone development. (Especially if you can get the discount he mentions in his post.)

Next Page »