Archive for the 'Cocoa' 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.

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

Cocotron

I don’t intend for this to become a link blog–not because of some high-falutin’ ideals, but because I assume most potential readers are at least as connected into the Mac dev community as I am and will have already heard the latest cool news.

But the latest post by Glen Aspeslagh describes Ecamm Network’s usage of a project which seems to deserve increased exposure: Cocotron, “an open source project which aims to implement a cross-platform Objective-C API similar to that described by Apple Inc.’s Cocoa documentation.” Or, as glibly summarized by the Ecammeratus: “Wrote a Cocoa app? Just add a new Xcode target, hit compile and out shoots a Windows version.”

Sure, it doesn’t work perfectly, but Glen’s warts-and-all description sounds promising. If you have a product that could benefit from a Windows equivalent please give Cocotron a look and contribute code–so it will be easier for me to use when I come up with a product that could benefit from it.

Adding Frameworks in Xcode 3.1

This is one of those cool little tidbits I learned during a WWDC session and can share now that Xcode 3.1 is out: Xcode 3.1 has changed the way you should add Apple-supplied frameworks. Although Apple claims in the Release Notes (you have read them, haven’t you?) that the process has been “simplified,” the method isn’t really apparent from within Xcode.
(Read the article)

NSArray and stringWithFormat:

The standard Cocoa method for a string with multiple replacements is [NSString stringWithFormat:]. To build a standard analogy string from the SATs:

	hand : palm :: foot : sole

you would break out each of the replaceable elements into separate strings and replace them in the format string with the placeholder ‘%@’. (There are many other format specifiers–look up printf()–but ‘%@’ is very common in Cocoa since it specifies an Objective-C object, not just a simple number or C null-terminated string.)

	NSString * format = @"%@ : %@ :: %@ : %@";

To create the desired string:

	NSString * myString =
	   [NSString stringWithFormat:format,
	                              @"hand",
	                              @"palm",
	                              @"foot",
	                              @"sole",
	                              nil];

If you want to create a different analogy string, just call stringWithFormat: again, using the same format string but different parameters following it.

The stringWithFormat: method takes a list of objects, and the nil parameter indicates the end of the list. If you want to manage the list of substitution parameters, though, you shouldn’t need that nil since NSArray knows how many elements it contains. Unfortunately, there isn’t a method like stringWithFormat: which takes an NSArray instead of a list of objects; there also doesn’t seem to be a simple way to convert the contents of an NSArray to a nil-terminated parameter list.

How then can you make this templating more dynamic at runtime by storing the list in an NSArray?

(Read the article)