Fixing Applescript
Posted on June 3, 2008 by Brian Webster
Filed Under Programming, Development | 1 Comment
After reading Daniel Jalkut’s post about replacing/supplementing Applescript on the Mac with Javascript (or perhaps another scripting language such a Ruby or Python), it got me to thinking about what exactly it is about Applescript that tends to trip people up. Would it be possible to figure out what the problem areas are, and just fix Applescript in those areas? There would be problems to this approach, the most prominent one being backwards compatibility. Some of the problems are fundamental enough that, if you fixed them, it would cause existing scripts to break. I believe Apple actually had plans a few years back of making a “new” Applescript that mostly acted like current Applescript, but was in fact a separate language and made an explicit break with previous versions of the language. Kind of like Carbon, where 80% of the stuff would work fine, but that problematic 20% would need rewriting under the new system.
So, what exactly are the problems that vex Applescripters so? There are quite a few, but here are some of the ones I can think of.
Lack of basic language features
Many modern scripting languages come with a fairly hefty set of built in data types and functions (or classes and methods for OO languages) that support a wide array of built-in functionality. Applescript has its own set of functionality, but for many standard tasks, it frequently either lacks the ability to do so at all or supports things but in a very hard to use or unintuitive way. A few examples include:
- Sorting an array of strings: Javascript has Array.sort(), Applescript has nothing.
- String manipulation, such as splitting strings apart, easily extracting substrings, etc. Some of these things can be done in Applescript, but are much much harder than they should be. (How many people know about “Applescript’s text item delimiters”? OK, both of you can put down your hands now)
- Mutable arrays/lists. Applescript lists support some operations, such as concatenating two together into one, fairly easily, but good luck if you want to do far out things like inserting a new object into the middle of a list, or delete an item from a list. Most of these things involve twisting yourself in a knot, splicing lists apart and back together again.
- Mutable dictionaries/records. See above.
This is just a small sample, I’m sure there are many other things that are pretty standard in other languages that are absent from Applescript, or hidden away in the Standard Additions scripting dictionary somewhere.
File references are the devil
There are at least 5 different ways I can think of to refer to a file using Applescript (alias, POSIX file (a.k.a. file URL), Finder style object specifier, POSIX path, Carbon path). Different applications use different data types in different places, and will often barf back errors if you don’t use just the right kind of file reference. Figuring out how to translate from one kind to another is often maddening. Here’s an example from one of my own scripts, which uses three of the five types in a single line:
set helpFolderPath to POSIX path of ((folder “Help” of folder “en.lproj” of ptFolderAlias) as alias)
Files really need to be treated as first class citizens, with support built in to the language, and without needing to rely on the Finder for all file system access. Or wait, am I supposed to rely on System Events now instead? Or maybe a “do shell script” call to ls on the command line? Oh, the pain.
Scripting dictionaries
This is one of the biggest hurdles that a lot of beginning scripters have with Applescript, is understanding how scripting dictionaries work. Tools like Script Debugger are extremely helpful when it comes to exploring an application’s dictionary (I hardly look at the dictionary anymore these days, and just go right to the explorer pane and start drilling down), but while $199 is a fair price for a developer, most people aren’t going to want to drop that sort of change just to learn Applescript. Script Editor did get a pretty good upgrade in Tiger, but I think it needs more work to help beginning scripters understand how to explore and use scripting dictionaries.
The death of recordability
Another invaluable tool for beginning scripters which is all but dead is application recordability. Back in the OS 9 days, you could hit the “Record” button in Script Editor and go perform operations in other applications, and the equivalent script commands would magically appear in Script Editor. This was a great way to quickly learn the commands to use to do certain things you already knew how to do using the GUI of the application. Since OS X, recording has basically gone away. The only applications I know of that are still recordable are the Finder and BBEdit/TextWrangler. Cocoa has zero support for recordability. Theoretically, you can use the Carbon APIs to do this still. I actually tried once, and gave up after a couple days of banging my head against the wall. I’d love to see recordability come back, with a whole new approach if necessary, with full Cocoa support.
Applescript does have a lot going for it, but is hamstrung by a lot of these types of issues and prevented from reaching its full potential. Replacing it with another language is one way to go, but fixing Applescript also has a lot of potential. This above list is just a sample of some of Applescript’s shortcomings (if you have your own pet peeves, feel free to express them in the comments). The idea of redesigning Applescript from the ground up, with nearly 20 years of experience to build on, is very appealing, but who knows if Apple will ever have resources to devote to a project like that.
Optimization for Dummies
Posted on November 23, 2007 by Brian Webster
Filed Under Cocoa, Programming, Development | 2 Comments
A somewhat inconspicuous looking article on optimizing third party code has stirred up quite a conversation/flame war among many in the Mac developer community. The comment thread on the article is already quite long, and it seems to me that the people with opposing viewpoints are just talking right past each other at this point, so I thought I’d add in my own perspective here.
The jist of the article is that the author, Ankur, needed to draw some gradients in one of his applications, downloaded the source code for CTGradient, an open source library that provides a class to draw various types of gradients, and decided that it had way more functionality than he needed in his own program. So, he went through the code and basically removed everything he didn’t need for this single application. That’s all fine and good, and the article is actually an interesting look at performing various refactorings and dead code removal.
The problem arises in that he implies that if a developer decides to use some open source code and doesn’t go through and strip out every ounce of functionality that they’re not immediately using, that means that they’re encouraging “code bloat” and that their code is not “optimized”. Several commenters asked what kind of performance/memory gain he actually saw, and the only numbers he provided were from the “Real Memory” column in Activity Monitor, which is a pretty crude measure. The conversation went downhill from there.
I think one main point of miscommunication here is over the terminology the original author uses for some of the things he’s talking about. When you talk about “optimizing” code, I, and most other developers I know of, think of making the code run faster. The author reinforces this by stating “…you can optimize this thing till it runs like a Ferrari”. Certainly sounds like he’s talking about making the code faster, but the vast majority of what he’s doing is simply stripping out code that he’s not going to be using. This has pretty little effect in and of itself - it saves a few KB in disk space, and if the code truly is unused, it probably won’t even get paged into memory in the first place. There are a few places where the code probably runs faster, but the gains look pretty minimal in the big picture. However, arguing the nitty gritty details about his particular optimizations is missing the bigger point…
Engineering is all about tradeoffs, and in computer software, this typically means choosing between things such as memory usage, disk usage, CPU usage, and so on. Every one of these, however, inevitably comes up against the restraint of development time. You can spend days, weeks, or months optimizing your code in various ways, but it’s all for naught if you don’t eventually ship your application. This means that you can’t do everything, and have to pick and choose what areas of your code to work on, whether to add new features or shore up existing ones, and how much time to spend optimizing performance and memory usage.
What is conspicuously missing from the article is any sort of evidence that CTGradient was actually causing any sort of performance or memory problem in his application in the first place. Now, may more have gone on that he didn’t include in his write-up, but it sounds like he simply looked at the code, decided that it was obviously too big and bloated, and set to work spending quite a bit of time hacking it down to the bare minimum he needed.
Finding and fixing performance and memory problems in real applications, however, is rarely so simple. It’s rare that you can glance at a piece of code and immediately deduce that it’s going to be problematic for your application, causing slowdowns or whatnot. Most such bottlenecks are discovered as a result of rigorous testing, using tools provided by Apple such as Sampler, Shark, and Instruments (among others) to dig into the details of what your app is actually doing and where it’s spending its time. Upon discovering such a problem, you can then go in and spend your precious time fixing what most needs to be fixed. It’s not that the modifications he makes don’t actually reduce code size and memory footprint (they do) or increase performance (still not really sure about this without empirical data), but with testing first to find what needs fixing, the time spent doing all this could very well have been better spent fixing something that actually needs fixing.
I actually use CTGradient in a couple of my projects, and I use the code basically untouched. This is not because I’m “lazy” and would rather count my customers’ money while cackling evilly than spend the time to strip out everything I don’t use, but rather because I have plenty of other things to spend time on, optimizing my app in ways that make a difference, and adding features that people want and need. None of my tests of my drawing code have ever shown any performance problems arising from using CTGradient as-is, so my motto is, if it ain’t broke, don’t fix it. The critical flaw in Ankur’s argument in his post is that he never showed any evidence that anything was broken in the first place.
Miscellaneous Leopard development gotchas
Posted on November 1, 2007 by Brian Webster
Filed Under Cocoa, Programming, Development, Tips & Tricks | Leave a Comment
I’ve been using Xcode 3.0 under Leopard to do my development since Leopard came out last week, and thought I’d share a few changes that tripped me up.
- I have a build script that I use to assemble the disk image for a new release of iPhoto Library Manager or PlistEdit Pro. The script creates the disk image using the
hdiutilcommand line tool. Everything went fine when building under Leopard except that, if you tried to mount the disk image on 10.3.9, it would refuse to mount. It turns out that Leopard’shdiutil, when running on an Intel machine, now defaults to creating an image with a GUID partition table rather than an Apple partition map like it used to. 10.4 and 10.5 can handle this fine, but 10.3.9 can’t and thus refuses to mount the image. The solution is simple: just pass-layout SPUDas an additional argument tohdiutilto force it to create an Apple partition mapped image. - One of the first thing many Cocoa programmers do when starting up a new project is to add a breakpoint on
-[NSException raise]. This makes it much easier to find out when exceptions are getting raised in your code and debug them quickly. I had this setup already, but when running under Leopard, I was getting exceptions thrown, but my breakpoint wasn’t getting hit. Turns out this has changed (at least for the cases I was seeing) under Leopard, so to experience the new exception debugging hotness, try a breakpoint onobjc_exception_throw. - Similarly, I was trying to break on NSLog to find out where some error messages were being printed out that I couldn’t track down. NSLog wasn’t getting hit, and it turns out that the printout was coming from CFLog instead.
Well, that’s what I’ve got for now, I may add more to the list later as I come across them. Hopefully this will help somebody out there (or maybe myself in a couple months when I forget and have to relearn this stuff over again).
Running FogBugz on Leopard
Posted on October 30, 2007 by Brian Webster
Filed Under Development, Tips & Tricks | 1 Comment
I use FogBugz as my main bug tracking and customer support system. It’s a neat application that runs on PHP and a web interface and allows me to both keep track of bugs/features in my development, as well as handle all tech support e-mail. It’s designed with a multi-user environment in mind, but works quite well for a one-man shop such as myself. The web interface is not as good as a true desktop interface could be, but it’s perfectly sufficient, and I’ve become quite dependent on FogBugz as part of my daily workflow.
Dependent enough that it was a rather rude (but not wholly unexpected) discovery to find that upgrading to Leopard pretty soundly hosed my FogBugz installation. Not that it went and deleted files or data or anything, but the setup was quite far from working normally.
The primary cause for this was that Leopard now ships with Apache 2.2, whereas Tiger came with Apache 1.3. All the various differences are well documented out there on the intertubes, but a lot of things, such as where configuration files are stored, changed between the two versions. For example, instead of httpd.conf being in /etc/httpd, it now resides in /etc/apache2.
I got that part figured out pretty quickly, but then when I went to start up the web server, I would get a message printed in the system console reading:
Oct 30 12:07:57 bw-mbp org.apache.httpd[11317]: httpd: Syntax error on line 484 of /private/etc/apache2/httpd.conf: Syntax error on line 8 of /private/etc/apache2/other/+entropy-php.conf: Cannot load /usr/local/php5/libphp5.so into server: dlopen(/usr/local/php5/libphp5.so, 10): no suitable image found. Did find:\n\t/usr/local/php5/libphp5.so: no matching architecture in universal wrapper
Hmmm, well, I do have a custom build of PHP5 (in /usr/local/php5, with additional extensions needed for FogBugz) and it seems to be finding that OK, but it’s complaining about architecture something-or-other. I’m still running on Intel, aren’t I?
[bw-mbp:~] bwebster% file /usr/local/php5/libphp5.so
/usr/local/php5/libphp5.so: Mach-O universal binary with 2 architectures
/usr/local/php5/libphp5.so (for architecture ppc): Mach-O bundle ppc
/usr/local/php5/libphp5.so (for architecture i386): Mach-O bundle i386
Yeah, that’s got an Intel build in there, that’s OK. What the heck is Apache’s problem?
[bw-mbp:~] bwebster% file /usr/sbin/httpd
/usr/sbin/httpd: Mach-O universal binary with 4 architectures
/usr/sbin/httpd (for architecture ppc7400): Mach-O executable ppc
/usr/sbin/httpd (for architecture ppc64): Mach-O 64-bit executable ppc64
/usr/sbin/httpd (for architecture i386): Mach-O executable i386
/usr/sbin/httpd (for architecture x86_64): Mach-O 64-bit executable x86_64
Oooh, I see 64-bit stuff in there, don’t I? I suppose that could be a problem if it’s trying to load a 32-bit library. Well, the packaged PHP that I installed from entropy.ch hasn’t been updated yet for Leopard, so I guess I’ll have to download and compile PHP myself so I can get in on the 64-bit goodness.
*insert footage of Brian downloading a bunch of stuff, typing ./configure and make, and seeing copious error messages fly across his terminal window*
Hmmm, OK, I think someone smarter than me is going to need to figure this stuff out. But I don’t have time for that, I want to get my FogBugz up and running so I don’t have to switch back to Tiger just to answer customer e-mail. If I could just force Apache to run as 32-bit instead of 64-bit, it should be able to load this PHP module just fine. Now let’s see, what would Dr. 90210 do…?
[bw-mbp:~] bwebster% man lipo
Yes, this is extremely hacktackular, and I’m sure there must be a better way to do this, but this is what I got.
[bw-mbp:~] bwebster% cd /usr/sbin
[bw-mbp:~] bwebster% sudo cp httpd httpd-fat
[bw-mbp:~] bwebster% sudo lipo httpd -thin i386 -output httpd
After making a backup of the httpd executable for safety purposes, the lipo commands sucks out all of the architectures included in the universal binary except the 32-bit Intel one (specified by “i386″). Apache can’t run as 64-bit if it doesn’t have a 64-bit binary!
After doing this, starting up the web server again worked just fine, and loaded the existing 32-bit PHP5 module. Once I got all my httpd.conf customizations moved over to the new location, that was pretty much all I needed to do. It also turns out that I probably would have run into this same problem for FogBugz specifically, since it loads its own fogutil.so PHP module which is also only available as 32-bit right now. I don’t know for sure, but I’m guessing people running on G5s, which also support 64-bit, would probably need the same trick, except replacing “ppc” for “i386″.
This is obviously a very poor long term solution, but if anyone needs to get FogBugz up and running on Leopard right away, this did the trick for me. Ultimately, getting FogBugz to work hack-free will require someone to get a 64-bit build of the PHP5 Apache module figured out, as well as Fog Creek providing a 64-bit build of their own Apache module. And of course what I’ve outlined here is totally unsupported by Fog Creek, so proceed at your own risk!
iPhoto Library Manager and Leopard
Posted on October 12, 2007 by Brian Webster
Filed Under Development, iPhoto Library Manager | 1 Comment
I just thought I would drop a quick note regarding plans for Leopard compatibility for iPhoto Library Manager. The short version is that iPhoto Library Manager will support Leopard fully by the time Leopard comes out. Yay! Since things can change and break things at the last minute with new OS releases, I won’t actually be releasing a Leopard compatible version of iPLM until I can actually test it with the final version of Leopard, but I’ve got the big stuff figured out already. For those interested in the nerdy technical details, read onward.
Leopard will require some changes in the way iPhoto Library Manager works under the hood. iPLM uses the Input Manager mechanism of Mac OS X to load a bundle of code into iPhoto which supplements iPhoto’s Applescripting capabilities, which is what makes features such as copying albums and merging libraries possible. Some other programs, such as Inquisitor and 1Passwd also use input managers to implement their functionality. However, as has been reported by Ars Technica and discussed on some other blogs, input managers are no longer going to be supported under Leopard.
Other developers have found other methods to do what they need to do under Leopard, such as 1Passwd, whose developers say they are going to switch to a WebKit plugin, which works well for them since their product is web browser oriented. iPhoto Library Manager is going to take a different approach though.
One difference between iPLM and some other apps that use input managers is that iPLM only actually needs its code to be loaded when it’s actively doing something with iPhoto, like copying some albums between libraries. It doesn’t matter if the code is loaded every time iPhoto is launched, unlike say, Inquisitor, which pretty much always has to be there to be of any use.
So, instead of a plugin based approach, under Leopard iPLM will use a handy little feature of the OS X dynamic linker, the DYLD_INSERT_LIBRARIES environment variable. Basically what this does is allow you to load additional dynamic libraries in an application (and even substitute for libraries the application is already linked to). The most well known usage for this feature is the MallocDebug developer application, which loads a custom debug version of the malloc library that replaces the normal system library and provides all sort of information on memory usage in the application being debugged.
The downside to this approach is that it requires relaunching the application in question in order to load the additional code, since you have to set up this environment variable and then launch the application yourself. So, for something like Inquisitor, launching Safari directly from the dock would not load the code automatically. There would have to be a separate program that performs the special setup and launch Safari itself, which would be a pain in the butt for users. However, this isn’t really a problem for iPLM, since it has to relaunch iPhoto multiple times during an album copy anyway, so having to do the special setup doesn’t really change the flow of things at all.
There are a couple other upsides to this approach:
- The code will only be loaded into iPhoto itself, unlike input managers, which load their code into any Cocoa application that runs. iPLM’s code doesn’t actually do anything unless it’s being loaded in iPhoto, but the input manager bundle still shows up in crash reports and such, which can be suspicious to others trying to debug a crash.
- Nothing needs to be installed! All the code can sit happily within iPLM’s application bundle, and there’s no need to update the bundle when iPLM is updated, or any of that hassle. This means I’ll actually be deleting more code than I’m writing in order to change to the new method.
The only feature that will be lost as a result of the change is putting the name of the current library in the title bar of the iPhoto window itself. This was a neat addition that I put in on a whim, but since the iPLM code will no longer always be running in iPhoto, this will be going away.
In retrospect, if I had known about this method of doing things back when I first wrote iPLM 3.0, I probably would have done it this way in the first place, since it’s less intrusive and uses a long standing feature of dyld that isn’t likely to go anywhere anytime soon. Like I said above, this method isn’t feasible for many programs that are currently using input managers, but this may still prove a useful technique to some other programs transitioning over to Leopard.
Subclassing NSSortDescriptor for fun and profit
Posted on September 7, 2007 by Brian Webster
Filed Under Cocoa, Programming, Development | Leave a Comment
In the project I’m currently working on, I’m using a pretty standard NSTableView + NSArrayController setup using the default sorting functionality. However, I found myself wanting to do some custom sorting, i.e. not just the usual sorting provided by @selector(compare:). This is made a little more complex by the fact that the columns of the table can be dynamically added and removed, so it’s not quite as simple as just changing the sort selector in Interface Builder. On top of that, I later found that I needed more customization still, because I needed to do special handling of nil values that was different from NSSortDescriptor’s behavior.
So, I set off to make a custom subclass of NSSortDescriptor. I can just override compareObject:toObject:, easy as pie! Right? Er… not quite. There really isn’t any information at all in the Cocoa docs about subclassing NSSortDescriptor, and there are a few gotchas that aren’t necessarily obvious when implementing the subclass, especially if you’re using it with an NSTableView.
To begin, I made my subclass (ITSortDescriptor) and overrode the compareObject:toObject: method. This worked fine to begin with, but I discovered that if I clicked on a table column to change the sort order of the table, it would soon revert to the default sort behavior. After some debugging, I discovered that the reason for this was that NSTableView was making copies of the columns’ sort descriptors using the NSCopying protocol. NSSortDescriptor implements NSCopying, but apparently its implementation will always return an instance of NSSortDescriptor, even the object being copied is an NSSortDescriptor subclass. So, I implemented copyWithZone: in ITSortDescriptor to return an instance of the subclass rather than a plain NSSortDescriptor. The implementation is pretty straightforward:
- (id)copyWithZone:(NSZone*)zone
{
return [[ITSortDescriptor alloc] initWithKey:[self key] ascending:[self ascending] selector:[self selector]];
}
This solved the problem for some cases, but there were still times when the column would revert to its old sorting behavior. I narrowed it down to when the table was already sorted by the column in question, and then you clicked on that column again to reverse the sort order. Apparently, NSSortDescriptor’s implementation of reversedSortDescriptor suffers from the same problem as its implementation of copyWithZone:. Overriding that in a similar manner then fixed that problem:
- (id)reversedSortDescriptor
{
return [[[ITSortDescriptor alloc] initWithKey:[self key] ascending:![self ascending] selector:[self selector]] autorelease];
}
To be really cool, instead of having [ITSortDescriptor alloc], that could instead be [[self class] alloc], but that would only really be useful if that’s what NSSortDescriptor did itself.
So with those modifications, I now have my table sorting just the way I want it. I thought I’d blog this so that anyone else who came across this stuff and was banging their heads against the wall might find it and save themselves some pain.
iPhoto 7/’08 observations
Posted on August 9, 2007 by Brian Webster
Filed Under iPhoto, Development, iPhoto Library Manager | 14 Comments
I’ve only been playing around with iPhoto 7 for a little bit now, but I’ve found some interesting nuggets on how things have changed in comparison to iPhoto 6. And yes, the official version number for the new iPhoto is 7, even thought it’s part of iLife ‘08. Thanks for not making things totally confusing, Apple. *sigh*
Events are the new Rolls
As I suspected might be the case, it appears that the new Events feature in iPhoto 7 is, structurally speaking, a rebranded use of Rolls from iPhoto 6 and earlier. In fact, I don’t see the term “roll” used anywhere in the iPhoto 7 interface anymore. I’m happy with the new Events interface, as it is a marked improvement and much more useful than rolls were under iPhoto 6. At the core of things, they basically work the same, but there are a couple important differences in behavior.
Like rolls, events are mutually exclusive, so every photo belongs to a single event, no more, no less. However, in iPhoto 6, every distinct import was grouped into a single roll. In iPhoto 7, a single import can now result in multiple events, depending on what settings you have in the preferences, and the dates of the photos that were taken.
Library folders are now packages
In previous versions of iPhoto, your library folder was just that, a folder. It appeared as a normal folder in the Finder, and you could dig through it and mess with things just as easily as any other folder. In iPhoto 7, Apple has decided to make iPhoto folders into packages instead. A package is simply a folder that doesn’t appear as a folder in the Finder. Most applications are actually packages (or rather, a special type of package called a bundle), and many other things, from plugins to documents are also marked as packages. You can still see what’s inside a package by control-clicking it in the Finder and selecting “Show Package Contents”.
This may cause a little terminology confusion in the short run, as the term “iPhoto library folder” is used fairly pervasively, but I think in the long run this is a good move by Apple. Countless people have unknowingly borked their iPhoto libraries in various ways by moving stuff around inside the library folder. This is actually not unreasonable behavior, but iPhoto reacts very poorly to having its library messed around with. So, my basic reaction is, “What took them so long?”.
For those curious in the technical details, iPhoto libraries don’t require an extension, as is the norm for most applications that store their data in packages, but instead have their “Is Package” bit set so that the Finder displays it as a package, even without an extension. It also sets the type/creator on the folder so that the library is displayed as a pretty icon in the Finder, as well as a Contents/PkgInfo file containing the same information.
Auto import folder
I don’t see this mentioned anywhere in the documentation, but there is now a new folder inside the library named “Auto Import”. It appears that how this works is, if you put some photos into the Auto Import folder, then the next time you launch iPhoto, it will look in that folder and import any photos it finds there. It does delete any photos in that folder after importing them. There is also an “auto import” Applescript command, but calling it doesn’t seem to do anything, at least not as far as I can see. I have a feeling this may have been a feature that was pulled out late in development, and they just forgot to remove the Applescript command and the actual folder inside the library.
New keyword interface
Another iPhoto release, another new interface for assigning keywords. By my count, this is at least the 4th different interface iteration for this feature in iPhoto. I also think this is the first time that the new interface has actually been an improvement over the old one.

In iPhoto 7, you can actually edit keywords directly inside the main viewer. This is quite cool, as it will autocomplete existing keywords as you type, and if you type a new keyword and type a comma, it will automatically create a new keyword with what you typed. This is a vast improvement over iPhoto 6, where you had to go into the preferences window just to add new keywords to your list.
But how do you edit the keywords of multiple photos at a time? This actually took me a good while to find, as the info window no longer contains a tab for editing keywords as it did before, and the keywords pane/button no longer exists down in the lower left corner of the window. I eventually found it, under the Window menu, there is a “Show Keywords” item that brings up a window with all your keywords.

From this window, you can select multiple photos, and then click the keyword buttons to assign/unassign keywords to the entire selection. You can also drag keywords up to the “Quick Group” area above and assign one letter keyboard shortcuts to them. For example, if I have “n” assigned to the keyword “nebula”, anytime I have something selected in the main iPhoto window, I can just press “n” to add/remove the “nebula” keyword from the selected photos.
I think this is the first version of iPhoto that really has a good interface for assigning keywords. Don’t know what took them so long, but there it is. My only gripe would be to have a button available somewhere in the bottom section of the window to bring up the keywords window, as I can see many people never even realizing that it’s available. I was actively looking for it, and it took me a good couple of minutes to find it.
There are many other large and small new features in iPhoto 7, which I may go into in more detail later, but those are the things that popped out at me in the first couple of hours of playing with it. I’ll be posting more later with other nuggets as I find them.
Spotlight Browser
Posted on July 1, 2007 by Brian Webster
Filed Under Freeware, Development | 3 Comments
In some recent development work, I came to want to be able to easily display the Spotlight metadata for various files in the file system. There is a command line tool, mdls, that lets you do this, but using it was kind of a pain and not very user friendly. There are approximately one kajillion programs out there that do various forms of Spotlight searching, but I couldn’t find one that just listed the metadata for files.
So, I grabbed Apple’s SimpleBrowser example code, made some modifications, and thus was born Spotlight Browser! It’s pretty simple, it just displays a Finder-like column browser at the top of the window that lets you browse through the file system, then displays the metadata value that Spotlight has indexed for the selected file in a table beneath the browser. You can also drag a file onto the window or to the dock icon to make the browser jump to that location.
I figured other people might find this useful and decided to release it, along with the source code as a free download, which you can get here.
WWDC 2007
Posted on June 18, 2007 by Brian Webster
Filed Under Apple, Development | 1 Comment
Well, I just got back safe and sound from the week long Apple geek-fest know as WWDC. I hadn’t been to the conference since 2001, back when I was still a student going with a free pass provided by Apple’s student developer program. That was back in the heady days of Apple’s reemergence and the dot com bubble, when there were about 1/4 as many people, it was still held in San Jose, and Jamba Juice flowed like water…
Uh, what was I saying? Oh yeah, WWDC 2007! It really was amazing how many people there were this year, enough that it got me wondering if they’ll have to change venues in the future if attendance keeps growing like it has been. They couldn’t fit everyone in the room for the keynote, so lots of people had to watch from the overflow rooms, and there were also a fair number of sessions that filled up and threatened to violate the fire code.
The keynote didn’t hold many surprises, but Leopard still looks like it will do well once it’s released. My only gripe was Steve Jobs trying to pass off developing web apps for the iPhone like it was something spectacular. Sorry Mr. Jobs, your audience just isn’t that gullible. You can’t sell a Whopper and tell them it tastes like filet mignon. I understand why they wouldn’t be able to provide a full OS X based SDK yet, especially for the first release of the product, but I would have much rather he just admitted “Yeah, it’s not ready yet, but while we’re working on that, you can still write web apps for the iPhone. We’ll get working on the real thing right away though.”
The upcoming stuff in the real OS X is looking pretty sweet though, and I definitely learned a lot at the sessions. I found out that with Time Machine, it will xxxx xxxxxxx xxxxx xxxxx xxxxxxx xxx xx xxxxx and also xxxx xxxxxxx xxxxx xxxxx xxxxxxx. The Core xxxxxxxxx talk was my favorite though, where they had this really cool demo that made the xxxx xxxxxxx fly around over xxx xxxxxxx xxx and even if you xxxx xxxxxxx xxx xxxxxx x xx xxxxxxxxx xxx, it will still slice through that red ripe tomato! Oh, and did I mention that all the material presented at the conference is confidential? Yeah, bummer. But trust me, it’s cool.
So, after a week of sitting on my butt in uncomfortable chairs, I am glad to be back home, sitting on my butt in a much more comfortable chair. Now if you’ll excuse me, I have a Leopard beta seed to install… ![]()
Gathering data with PlistEdit Pro and Applescript
Posted on March 15, 2007 by Brian Webster
Filed Under Development, Tips & Tricks, PlistEdit Pro | Leave a Comment
All sorts of information is stored in property lists these days. It’s a simple but flexible format, used for simple stuff like application info and preferences to being the basis for some apps entire file formats. Browsing through property lists is fine and all, but there are some times when you need something with a little more oomph to sensibly look at the data you’re looking for. Some simple but well placed Applescript code in conjunction with PlistEdit Pro can yield some very useful results.
For example, in my various iPhoto related development, I’m often found in far too close contact with the AlbumData.xml file that iPhoto writes out, which is really just an XML property list. This file stores information on all the photos, albums, and rolls that exist in the iPhoto library. I recently found myself needing to look through the ID numbers of all the albums in a library, looking for duplicates. After about 30 seconds of twiddling down triangles and scrolling, I realized I needed a better way to get at this data.
Enter Applescript
OK, so you can write an Applescript that will iterate down into all those plists and compile the data for you. It would probably look something like this:
tell application “PlistEdit Pro”
set albumIDList to {}
repeat with albumPlist in plists of plist “List of Albums” of plist of document “AlbumData.xml”
set albumIDList to albumIDList & value of plist “AlbumId” of albumPlist
end repeat
return albumIDList
end tell
Well, that works OK, but with judicious use of Applescript’s test clauses, getting a list of the album IDs could be done in a single statement:
tell application “PlistEdit Pro”
get value of plist “AlbumId” of every plist of plist “List of Albums” of plist of document “AlbumData.xml”
end tell
OK, that looks like quite a bit to swallow at once, so let’s break that down, from right to left:
plist of document "AlbumData.xml": gets the root plist of the AlbumData.xml document, which is assumed to already be open in PlistEdit Pro. Result: a Dictionary plistplist "List of Albums" of...: gets the plist under the key “List of Albums” in the root plist. Result: an Array plistevery plist of...: gets every child of the “List of Albums” plist. Result: a list of Dictionary plists.plist "AlbumId" of...: this is where Applescript gets cool - without having to write any silly loops, this statement iterates through the list of child plists, extracts the “AlbumId” child plist from each one, and returns a list containing the result, no muss no fuss. Result: a list of Number plists.get value of...: again, loops through the list of “AlbumId” plists we just got and extracts the value property of each one, resulting in a simple list of the ID numbers themselves, which is exactly what we’re after. Result: a simple list of numbers
Not only is this version of the script somewhat simpler, but it’s also quite a bit more efficient, in that it doesn’t have to send individual commands to retrieve each ID and concatenate it onto our result list. This isn’t too bad in this example, but the difference can be quite significant in some applications (hint: try something similar with retrieving some message info from Mail and marvel at the speed difference)
Reading the results
Running this script in Script Editor should result in something like:
{2, 9.99001E+5, 9.99002E+5, 2580.0, 2578.0, 2579.0, 106.0, 107.0, 108.0, 357.0, 586.0, 587.0, 517.0, 427.0, 486.0, 411.0, 469.0, 538.0, 392.0, 442.0, 452.0, 458.0, 2265.0, 637.0, 655.0, 729.0, 2798.0, 2815.0, 3265.0, 3300.0}
But why look at it in that hard to read form, when you can just feed it right back to PlistEdit Pro for display?
tell application “PlistEdit Pro”
set albumIDList to value of plist “AlbumId” of every plist of plist “List of Albums” of plist of document “AlbumData.xml”
make new document at front of documents
set value of plist of front document to albumIDList
activate
end tell
Now you have a nicely displayed plist that you can sort, save, or do anything else you need to.
Applescript is commonly thought of as mainly being for automating repetitive tasks, but with a little practice, it can also become quite useful for one-shot items like this.