Archive for November, 2008

The Best of Domain of the Bored

Saturday, November 29th, 2008

This morning, I went through my old posts and tagged some of them as “bestof”. With a little query-variable magic, I was able to create an Atom feed containing several random best-of posts.

feed://feeds.feedburner.com/bestofdomainofthebored

You may want to check out that feed and see what posts you might have missed the first time I published them.

Framework Friday postponed

Wednesday, November 26th, 2008

The framework I picked turned out to be buggier than usual. Filing those bugs, plus some other things I have on my plate, means I won’t get done anytime close to last Friday.

So, last week’s Framework Friday post will appear on the next Framework Friday instead.

Sorry.

How to work with a bound-to array

Wednesday, November 26th, 2008

You have a model object with an array property:

@property NSArray *framistans;

You also have an array controller whose contentArray binding is bound to this property.

How do you add an object to the array?

Wrong #1: Direct manipulation

[framistans addObject:newFramistan];

The array controller will not notice this change. Worse, the value of your array no longer matches the value your array controller last saw. (For one thing, your array is now one object longer.)

Wrong #2: Use the array controller’s add: action

[arrayController add:nil];

This works, but now you need to go looking for that object. The proper way would be to get the binding info for the array controller’s contentArray binding, then ask the bound-to object for its array, and get the lastObject of that array.

More likely, you’ll hard-code knowledge of which object and which property it’s bound to. Good luck when you change the binding!

Oh, and in a model object, this breaks the separation between your model and everything else. Your model should know nothing of your UI, so that you can replace the UI wholesale if ever you want to (for example, if you make a CLI or web-based version of your app) and keep the same model.

Wrong #3: Add the object to the array controller’s content array

newFramistan = [arrayController newObject];
[arrayController addObject:newFramistan];

This works, and at least you already have the object on hand. But you’re still giving your model knowledge of the array controller, so you’re still breaking separation.

Almost right: Add it to the mutableArrayValue for your property

[[self mutableArrayValueForKey:@"framistans"] addObject:newFramistan];

This works, and it’s clean.

The only problem with it is that it’s too heavyweight: you’re creating this proxy object just to mutate a property. The most appropriate use for mutableArrayValueForKey: is if you want to pass a mutable array to another object, and you want that array to actually be a property of another object. This is a very rare case—I’ve never needed to do it.

For this problem, there is a better solution.

The Right Way: Use your accessor

UPDATE 2008-12-02: Don’t do this. See the section I added below.

[self addFramistansObject:newFramistan];

Look at that.

Beautiful, isn’t it?

It’s almost as short as the direct array access, and it does the Right Thing with KVO. Your array controller will find out about the change without you having to tie knowledge of the array controller into your model.

We should also look at the accessor:

- (void) addFramistansObject:(Framistan *)newFramistan {
    [framistans addObject:newFramistan];
}

Also short, and also beautiful. (Yes, that is the complete definition of the method. I’m not eliding anything.) And there are no separation violations here, either: It’s pure model.

When you bind the array controller to your object, KVO wraps your object and all its KVC-compliant accessors, including this method. Its implementation performs the proper KVO notifications around a call to your implementation, which means you don’t have to do any KVO work at all.

UPDATE 2008-11-30: Note that you must also implement removeKeyObject:; if you don’t, addKeyObject: will not post the KVO notifications. You must implement both. Thanks to Dave Dribin, who emailed me about this.

ADDED 2008-12-02: The current Right Way: Use indexed accessors

KVO does not work correctly with addKeyObject: and removeKeyObject: for array properties.

The problem is that it treats those methods as set accessors and posts set-mutation notifications, regardless of the fact that it’s an array property. This doesn’t seem to cause a problem with Bindings (as of 10.5.5), but when I tried observing the property using KVO directly, I got a crash every time, as it tried to send NSSet messages to my NSArray.

Instead, you’ll need to use indexed accessors:

[self insertObject:newFramistan inFramistansAtIndex:[self countOfFramistans]];

As with addObject: and removeObject:, you must implement both of the pair. Here’s what removal looks like:

[self removeObjectFromFramistansAtIndex:[self indexOfObjectInFramistans:framistanToRemove]];

indexOfObjectInKey isn’t actually something KVC looks for, but it fits the use case and beats getting the entire array (which generally means copying it) just to find the index of one object. And you have to implement all these methods anyway.

Note that you should not implement addKeyObject: and removeKeyObject: at all for an array property, even to call the indexed methods. That’s because KVO always posts its erroneous set-mutation notifications around your addKeyObject: and removeKeyObject: methods, regardless of how you implemented them.

Thanks again to Dave Dribin, as most of this came up in the same email thread.

Further reading

Sources of free music

Tuesday, November 25th, 2008

By which I mean, sources that you can check periodically or subscribe to to receive a steady stream of free music.

For music podcasts, use a regular RSS reader (or a dedicated podcatcher, if you have one), not iTunes. I’ve had problems convincing iTunes to accept files into its Music library that I’d downloaded through its podcatcher.

These are some sites that I don’t personally subscribe to, but am aware of and occasionally benefit from indirectly (e.g., when Largehearted Boy posts a link to a Team Love track):

  • A site called RCRD LBL has a blog called RCRD SELECTOR, which provides a few free songs per day. The feed doesn’t use enclosure tags, which makes podcatching difficult, but I’m listing it anyway in case you’re OK with that.

  • You Ain’t No Picasso is primarily a music blog, although it has the occasional non-music-related post. Not every post has MP3s on it, but most do. Has a feed, but no enclosure tags. (Added 2008-12-17; thanks to Mike Krieger for linking to one of their posts on Twitter, and Colin for retweeting that link)

  • The Hype Machine aggregates a lot of MP3 blogs, including the aforementioned Stereogum. Has a feed, but no enclosure tags. (Added 2008-12-17; thanks to Colin for suggesting it on Twitter)

  • Team Love is a record label that gives away songs on their Library page. There’s no dedicated Library feed, so you’ll have to check back periodically (Tuesdays?).

    One thing you’ll notice is that the front page says in one paragraph that the Library is “open to the public 24/7”, and then in the next paragraph that you’ll need to open an account. There is some open-to-the-public access on the right side of the page (“Artists” and “Featured MP3s”); I don’t know what an account gets you.

    Added 2008-12-17. Thanks to Matt Morrell, who is a musician himself (with at least one song of his own available for free) and sent me the link on Twitter.

  • KRCW’s Today’s Top Tune podcast is another weekdaily rock-music podcast (with, of course, a a podcast feed). Note that not every episode is a song; for example, right now, the oldest of the three episodes in the feed is an interview with Tony Hawk. Note also that the song files have borked tags, with the artist in the title tag and the song title nowhere; you’ll have to fix these yourself.

    KCRW has other shows, but it looks like Today’s Top Tune is the only one you can stock your music library from. (Corrections welcome.)

    Thanks to Steven for linking to Today’s Top Tune in a comment.

If you know of other, similar sources, I invite you to link to them in the comments.

UPDATE 2009-03-26: Segregated sites I don’t subscribe to into their own list, and added Largehearted Boy, NME, and Spinner.
UPDATE 2009-04-06: Demoted KCRW to the sources-I-don’t-subscribe-to list. I get enough music from other sources now that I don’t care about it enough to deal with its broken tagging scheme.

Manpage Monday: afconvert(1)

Monday, November 24th, 2008

afconvert is a command-line utility that uses Core Audio to convert audio files from one format to another.

The manpage is actually pretty sparse (like the rest of the Core Audio documentation); you’re better off reading the command-line help:

% afconvert -h

A simple example is to convert an AIFF file to AAC in an MPEG-4 file:

% afconvert -f 'm4af' -d 'aac ' -b 98304 Recording.aiff

The resulting file is 96 kbps (98,304 bps) and is named “Recording.m4a”.

UPDATE 2008-11-26: Corrected permalink and title to include the section number.

iTunes smart playlist: Music only

Sunday, November 23rd, 2008

A smart playlist selecting items that are not podcasts, whose Kind does not contain “URL”, [v]“ideo”, or “movie”, that are not in the Audiobooks special playlist, and whose Genre does not contain “Comedy” or “Spoken Word”.

Some explanation:

  • Kind does not contain URL: Excludes streams
  • Kind does not contain ideo: Excludes music videos
  • Genre does not contain Comedy or Spoken Word: Excludes anything that isn’t actually music

Solved problems

Sunday, November 23rd, 2008

Here are some types of apps that I’m tired of seeing over and over again on the iPhone App Store. In some of these categories, I’ve picked a winner that completely solves the problem; you’re welcome to nominate winners for the others.

  • Flashlight (solution: myLite)
  • Tip calculator (solution: Calculator—seriously, is subtotal × 0.2 so damn hard?)
  • Any app with a checkmark icon, regardless of function: Think of a different icon, please. At this point, you might as well just make the word “app” your icon.
  • App to help you find your way back to your parked car: The main problem is that all of these use Core Location rather than just tracking movement through the accelerometer. That makes the app useless if you don’t have an iPhone 3G and you’re out of cell range or don’t have a cell antenna (iPod touch).
  • One-tap contact dialer (also includes 911/999 dialers)
  • Apps that fake receiving a phone call
  • Fortune-telling/decision-making apps
  • The Puzzle desk accessory
  • Sudoku (solution: ACTSudoku and its free light version)

There’s nothing wrong with competition, but these are saturated markets. If you’re not going to solve the problem in a completely different way (e.g., by not using Core Location to set the location of the parked car), then don’t waste your time—write something else.

If you have any suggestions for other categories that should go on the list, feel free to leave a comment.

New service: Insert Mac OS X Build Number

Friday, November 21st, 2008

File: InsertMacOSXBuildNumber.zip

A service that inserts the build number (for example, 9F33) of your current Mac OS X installation.

The main purpose for this is so that, when filing bugs in Radar, you can precisely specify which build of Mac OS X you’re running. (Especially if you’re running a pre-release build of a future version of Mac OS X.)

I created it with ThisService, of course.

(And yes, I am also working on tonight’s Framework Friday post.)

Report-an-Apple-Bug Friday! 75: NSUserDefaults and /Library/Preferences

Friday, November 14th, 2008

This bug is NSUserDefaults does not look in /Library/Preferences. It was filed on 2008-11-14 at 23:09 PST.

(more…)

Framework Friday: OSAKit

Sunday, November 9th, 2008

Apologies for posting this late. I was finishing up the test app and filing relevant bugs.


So, how do you run an AppleScript script?

One way is NSAppleScript. The problem with that is that, in our experience on the Adium project, it leaks memory. Profusely. (Maybe this has changed; Adium has for a long time used a separate process for running AppleScript scripts.)

Another way is to use the Open Scripting Architecture API directly. But that API is pre-Carbon, making it painful to deal with. One specific problem is that the object types aren’t reference-counted.

The third way is OSAScript, one of the classes in OSA Kit.

Wait. OSA Kit?

Yes. OSA Kit is an Objective-C wrapper around the Open Scripting Architecture. Like QTKit (a similar wrapper around QuickTime), it’s a framework in Mac OS X that Apple added in version 10.4. It’s public, but undocumented: As of right now, searching developer.apple.com for that name yields exactly five hits, none of which are documentation of OSA Kit.

One of those hits is the list of system frameworks, which says that OSA Kit:

Contains Objective-C interfaces for managing and executing OSA-compliant scripts from your Cocoa applications.

OSA-compliant… like AppleScript!

The interface for OSAScript is the same as that of NSAppleScript, except larger: OSAScript is a superset of NSAppleScript. This is mostly because the OSA supports languages other than AppleScript, such as JavaScript (with this component). Running a script, for example, is no different:

NSDictionary *errorDict = nil;
script = [[[(OSAScript | NSAppleScript) alloc] initWithContentsOfURL:scriptURL error:&errorDict] autorelease];
result = [script executeAndReturnError:&errorDict];

But, unlike NSAppleScript, the OSA Kit does not stop there.

OSA Kit is to Script Editor as Image Kit and PDF Kit are to Preview. Apple removed those applications’ capabilities to a new framework, and rewrote the applications to use the new frameworks. In the process, they added features and made the existing features prettier.

In the case of OSA Kit, the new framework includes classes you can use to build your own Script Editor (or CLImax)—specifically, OSAScriptView and OSAScriptController. You may find these classes useful if you plan to embed some of Script Editor’s functionality into your application.

Of course, you don’t need to use OSA Kit from an application. Here’s a command-line tool I wrote:

File: OSAKit-osascript-1.0.2.tbz

A clone of osascript, written to use either NSAppleScript or OSAScript. The Xcode project contains two targets, one for each version.

There are very few differences between the two variants:

  1. Obviously, the OSA Kit version uses OSAScript, whereas the other version uses NSAppleScript.
  2. The OSA Kit version has an option to allow you to specify the language, and another one to list available languages. (NSAppleScript, as you might guess, only supports AppleScript.)
  3. The OSA Kit version can (theoretically) pass arguments to the script; NSAppleScript doesn’t support this.

OSA Kit does have some downsides:

  1. As I mentioned, it isn’t documented. All we have to go on are the headers.
  2. There’s not even sample code, other than the example I wrote and included in this very post.
  3. Calling a handler by name with arguments doesn’t work (hence the “theoretically” above). I believe that this is a bug in OSAScript; I have filed it, with a summary of -[OSAScript executeHandlerWithName:arguments:error:] always returns an error, never executes the handler.

There is also one potential downside: I don’t know for certain that OSAScript doesn’t leak memory the same way NSAppleScript does (or did). It’s worth trying, though, and it’s more capable anyway.

I consider the OSA Kit to be the future of running AppleScript scripts from Objective-C.

UPDATE 2008-11-09 13:18 PST: Replaced OSAKit osascript 1.0 with 1.0.1, which has a couple more sample scripts.

UPDATE 2008-11-09 17:40 PST: Changed link to CLImax. I had linked to Drew Thaler’s blog post announcing its re-release; now I’m linking to the actual product page, as saved by the Internet Archive’s Wayback Machine.

UPDATE 2008-11-11 20:43 PST: Replaced OSAKit osascript 1.0.1 with 1.0.2, which has better (more GCC-like) error-reporting.

Translation from marketing-speak to English of selected portions of the FAQ for “Disney’s FastPlay”

Thursday, November 6th, 2008

Disney’s FastPlay & EasyFind Menus FAQs:

1. What is Disney’s FastPlay?

  • Disney’s FastPlay is a new technology that puts you in control of your viewing preferences.
  • You can choose to use your remote and navigate through our user-friendly EasyFind menus, or you can simply put in the disk and go sit down and relax and the DVD automatically begins. You don’t have to push a button!
  • You can watch the feature presentation just like you would in theaters. After the trailers and feature, stay tuned for an exciting selection of Bonus Features.

We just start the movie without putting you through a menu.

[Emphasis mine in the above quote.]

2. What benefit will I receive from viewing a Disney DVD with Disney’s FastPlay?

2. What good is it?

  • Disney’s FastPlay takes away the extra steps that most DVDs require in order to watch the movie or Bonus Features.
  • If you don’t want to navigate to start the movie, Disney’s FastPlay navigates for you.
  • Disney’s FastPlay also gives you a look into the great Bonus Features that Disney DVDs offer.

Like we said, we just start the movie without putting you through a menu.

3. Why is Disney’s FastPlay not available on all Disney Titles?

Disney’s FastPlay technology was designed with families in mind. Many children under 8 years old aren’t able to easily navigate a DVD. It also gives parents the option to put a DVD on for their child/children without having to wait and navigate through the Menu.

Wait, did you ask us a question?

[snip]

11. What are EasyFind menus?

EasyFind refers to enhanced menus. The Main Menu, Set-Up Menu, and Bonus Features Menus have been enhanced to provide a consistent location for set-up options and Bonus Features on all Disney DVDs. …

We put the buttons in the same place every time.

Tabs vs. spaces redux

Wednesday, November 5th, 2008

Alice, who prefers four-space indents, wants this:

Four-space indents, with non-first lines of an Objective-C messages lined up on the colon of each argument.

Bob, who prefers eight-space indents, wants this:

Eight-space indents, with non-first lines of an Objective-C messages lined up on the colon of each argument.

Is it possible for this source code file to be written such that Alice and Bob each see what they want?

Yes, but not yet.

What they need to do is to use tabs only up to the level of indent of the first line, then spaces the rest of the way:

Screenshot demonstrating this with four-space indents.
Screenshot demonstrating this with eight-space indents.

Note that the contents of the file are the same in both of these images; the only change is the indent width. The characters shown in these two images produce the result shown in the earlier two images.

I say “not yet” because no editor currently does this. Xcode, for example, will use on each line as many tabs as it can fit, followed by < tabstop spaces. Other editors won’t line up the colons; they’ll just left-justify all of the non-first lines.

So Alice and Bob can each have the indent width they want; it’s just a pain in the ass for them to do the editing necessary to get it. Therefore, they won’t bother, just as I don’t.

So, consider this my call to the makers of all the editors to auto-indent the right way, as I have just shown it.

Added a few minutes later: Alternatively stated by Christopher Bowns on his blog post.