Still can’t GetLabel()

So we’re at a point in our development cycle where we can finally upgrade our toolset. Installed Xcode 3.2.3, using the LLVM-GCC4.2 compiler, the 10.6 SDK, and setting 10.5 as our minimum OS.

Of course now I compile code and lots of OS function deprecation warnings come up. Time to clean up the source code.

If you need to obtain a Finder label, the old-school way was to use GetLabel(). Even today we still have to use GetLabel(), despite the fact they have deprecated it since 10.5. And while they deprecated it in 10.5, they didn’t provide a replacement API until 10.6. Unfortunately this replacement API isn’t 100% workable.

1. It’s an Objective-C API, in AppKit. Specifically: -[NSWorkspace fileLabels] (and -fileLabelColors).

The old API was a pure C API so you could easily use it anywhere, and we use it in a pure C++ library. Fine. I can create a .mm file with an extern “C” function to provide my own C wrapper and mimic GetLabel()‘s API. But it’s just extra work.

2. It’s only available as of Mac OS X 10.6.

It’s not a huge problem, but it’s irritating they deprecate the old way and didn’t provide a new way until the next OS revision.

3. -fileLabels crashes.

Isn’t that wonderful? They provide a new API and the new API doesn’t work.

And it’s not like it’s any sort of difficult API to work with either. It’s just a simple call.

But how can you get it to crash? Simple. Call [[NSWorkspace sharedWorkspace] fileLabels] 3 times. The first time will be OK. The second time might generate the crash but could also just generate console messages. The third time, you should crash or certainly generate bad messages in the console. If you didn’t crash the third time, certainly on the fourth you should. But typically 3 calls and boom.

-fileLabelColors doesn’t have this problem.

Investigating it, it seems there’s something being double-released/freed/deleted inside of -fileLabels. You can turn on garbage collection and it won’t crash, but lots of ugly console messages are generated.

What also bugs me? How did this API ship with such a bug?  Didn’t they test it? Didn’t they unit test it? Did they only test it under garbage collection? Did they write the API only for the Finder and figure if the Finder wasn’t crashing that was a good enough test to say a public API for the OS would work?  I mean, I can understand complex bugs, I can understand how code paths can be what they are and how bugs can ship (been a professional software engineer for over 15 years). But something like this? I can’t see how this managed to get out the door.

*sigh*

rdar://problem/8301881 Seems it was also reported as rdar://problem/8084710.

So… there’s no GetLabel() replacement for me until they fix it, 10.7 if I’m lucky. Yes I’ve considered other workarounds, no they won’t work in my particular context, or with a lot of work I could get it working but it’s not mission critical and I have bigger issues to deal with.

Updated: Apple DTS wrote back saying this is a known issue being tracked under its original number: rdar://problem/7287108, which as you can see is at least the third report of the problem. So we can only hope Apple’s going to fix it, but I bet we won’t see it until 10.7 at the earliest.

4 thoughts on “Still can’t GetLabel()

  1. I stumbled on this entry while Google searching “sharedWorkspace fileLabels bug”. Wow. I thought I was going crazy. I’m quite new to Obj-C, and putting together a little tool that just returns a few of NSWorkspace’s methods. When I found this (yep… 3 times), I started thinking that I had some kind of problem in the code leading up to it, like something getting released when it shouldn’t be.

    While I’m not happy about a bug from Apple, I’m glad to see that it’s not just me and my code. I’ve got enough rookie mistake issues that I’m tracking down all the time without bumping into errors like this.

    • Yeah, it drove me crazy when I encountered it myself… and I could see how it’d drive a newbie even crazier. 🙂

      I hope Apple does fix it, tho I wouldn’t expect to see a fix prior to 10.7 (but I have no inside knowledge as to when/if it’ll be fixed).

  2. I was playing around with this today. I *appears* that the items put in fileLabels simply are lacking an retain. I don’t condone this method, since if you call it and they fix it, you’ll have memory leaks (although I could think of possible ways to get check for this).


    #import

    int main (int argc, const char * argv[])
    {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSWorkspace *wkspc = [NSWorkspace sharedWorkspace];
    for (int i = 1; i <= 10000000; i++) // for effect
    {
    if (i % 1000000 == 0) NSLog(@"Finished %d", i);
    NSAutoreleasePool * inner = [[NSAutoreleasePool alloc] init];
    NSArray *array = [wkspc fileLabels];
    for (id item in array)
    [item retain]; // if we didn't have this line, the [inner drain] call would crash on 3rd try
    [inner drain];
    }

    NSLog(@"Done!");
    [pool drain];
    return 0;
    }

    • Ah you know… I hadn’t thought about that — putting the retain on the label. I had tried retaining the labels array, but not the individual labels. No idea why it didn’t occur to me to try that. I’m not surprised that works, as it seems the problem is that something in the OS freed up the memory that shouldn’t have.

      Memory leak? Yeah, it would be, but crashing is a far worse problem. I guess the feasibility of the solution depends upon your needs.

      One consideration… there is the NSWorkspaceDidChangeFileLabelsNotification, which you could perhaps use as a way to free things up. Or perhaps, you obtain the items and make and use your own cache, get the notification, free your cache and then obtain from the OS again.

Comments are closed.