May 2008 Archives
Scripting Bridge is definitely one of the cooler additions to the toolbox that was added with Leopard. In a nutshell, it makes AppleScript palatable to those who loathe AppleScript. I don’t know what it is about AppleScript, but I always end up banging my head on seemingly simple problems.
Scripting Bridge reads an application’s AppleScript dictionary and creates a nice Objective-C API. The brilliant part is that you can access this Objective-C API from Ruby or Python, too. Scripting Bridge isn’t perfect, though, and one of the more annoying things is the warnings it spits out.
If you invoke SBApplication's +applicationWithBundleIdentifier:, you will often get a bunch of warnings printed out to standard error. This is not only annoying for GUI applications, as it clutters up the console output, it’s down right intrusive for command line applications. (r. 5964420)
This has bothered me for a bit, but while writing osx-trash, I finally figured out a way around it. It’s pretty simple: redirect standard error to /dev/null temporarily.
I’m a command line kinda guy. Always have been, and probably always will be. The GUI does have some advantages, though. For example, the Finder in Mac OS X moves files to the trash when deleting them, so you get a chance to resurrect them before actually removing them.
The Mac OS X command line is missing any way to move files to the trash, though. Sure there have been shell scripts ([1], [2], [3]) to move files to the trash, but they always have some limitations or annoyances. These solutions try to simulate how the Finder moves files to the trash, but usually miss a few details. Enter osx-trash.
Threaded programming on Mac OS X, as with almost any platform, is fraught with danger. One of the biggest snags is that AppKit, the GUI framework, is not thread safe. In order for things to work properly, you almost always need to update GUI classes from the main thread, only. Fortunately, Objective-C makes it relatively easy to run a bit of code on the main thread. If you’re on a background thread or in an NSOperation, you can invoke one of the performSelectorOnMainThread: variants of NSObject. For example:
[person performSelectorOnMainThread:@selector(setName:)
withObject:newName
waitUntilDone:NO];
This calls the -setName: method of the Person class, passing in a new name. You also have the option of waiting for the method call to finish before proceeding in the background thread.
There are a few problems with performSelectorOnMainThread: and friends:
- You can only pass a single argument.
- You cannot pass a primitive types.
- The syntax is quite verbose.
I’ve come up with a better way of doing this as a category to NSObject called dd_invokeOnMainThread. Here’s how the preceding call would look:
[[person dd_invokeOnMainThread] setName:name];
This solves all three problems of performSelectorOnMainThread: and friends:
- You can pass as many arguments as you like.
- You can use primitive types.
- The syntax is less verbose.
Thus, even a method call like this is possible:
[[someObject dd_invokeOnMainThread] setInt:5 withObject:foo];
I’m on this week’s Mac Developer Roundtable regarding source control management. This was the first podcast I’ve participated in, and I’m happy how it turned out. The fact that I don’t utterly hate my voice when I hear it is a little unexpected. Thanks for having me on Scotty.
I talk a bit about my experiences with Mercurial as well as some generic version control topics, like branching, merging, and tagging. I probably could have talked more about the advantages of Mercurial and distributed version control systems (DVCSs), but it was hard in such a short time.
I’m glad I was able to talk a bit about unconventional uses of DVCSs, such as managing Unix configuration files and using them to keep track of changes I make to Apple’s sample code. I’d like to elaborate more on these in a future post, but for now, enjoy the podcast.
