Archive for the 'Cocoa' Category

Reunification

Tuesday, February 2nd, 2010

A common question from people new to Objective-C is “why do I have to separately alloc and init? Why can’t I just call one thing and get a fully initialized object?”.

It’s certainly not how other environments do it. Usually, you call one function or class method, and you get an object. Cocoa makes you send two messages: one to the class, then another to the fresh, uninitialized instance you got back. What does Cocoa know that those other environments don’t?

There are two reasons why alloc and init are separate:

  • “NSResponder”* says that sometimes, NeXT wanted to initialize the same object multiple times.

    This is interesting, but horrifying to modern readers. Practically all init methods I’ve seen do not handle the case of initializing the already-initialized; they blindly assign newly created/retained objects to the ivars without checking for existing objects there.

    A bigger problem is when the init method releases the receiver and returns some other object; in the second message, the “other” object may in fact be the receiver (returned from the first message), so [self release] this time would be killing off an object that should stay alive. On the other hand, retaining the object before re-initializing it will create a leak if the object doesn’t release itself. Unpredictable behavior is bad.

  • On the same Stack Overflow question, Darren points out that alloc is shorthand for allocWithZone:; if allocation and initialization were merged in Cocoa, then, to maintain the same functionality, every initializer would need to take a zone parameter, and optionally come in a flavor without one. You can imagine how a proliferation of initializers would ensue.

    This is essentially what the documentation says: “Separating allocation from initialization gives you individual control over each step so that each can be modified independently of the other.” I.e., both steps can be customized, so they must remain separate so that you can customize either or both.

So, there are two practical reasons why Cocoa’s designers separated allocation from initialization.

But let’s revisit this with modern eyes:

  • As I mentioned, in modern Cocoa, initializing an instance again is risky at best. In practice, I don’t think anybody does it, and if anybody does, they probably feel guilty about it and mean to refactor that code “someday”.
  • Nobody uses zones anymore.

That blows those two reasons away.

So, let’s imagine what life would be like if they had never existed in the first place, and allocation and initialization had remained one task:

+ (id) newWithFramistan:(Framistan *)framistan {
    id obj = [super new];
    if (obj) {
        obj->framistan = framistan;
    }
    return obj;
}

Right away, you can see several advantages:

  • We can name our local variable “framistan”, not “newFramistan” or anything like that.
  • No more assignment in condition (if ((self = …))).
  • No more assignment to self (which should make Wil Shipley happy).
  • Eliminates the problem of [super init] returning a different object, whereupon you would have to release the receiver. Since the receiver is the class, there is nothing for the upstream-initialized object to be different from. If the superclass wants to return an existing object, it can just do that.
  • Related to the first point, we no longer have a name conflict between instance variables and local (especially argument) variables. In init methods, we resolve this conflict with style rules, such as the aforementioned newFramistan for locals or m_framistan for instance variables; in this newWithFramistan: method, the conflict doesn’t exist in the first place.
  • There is never an uninitialized object that the caller could leave lying around. We’ve all seen (or written) code like Foo *foo = [Foo alloc]; [foo init];; in this alternate universe, such faux pas are impossible.

There are trade-offs:

  • It’s one line longer. (Depending on your employers’ level of cluefulness, this may be a small advantage.)
  • Since you’re not in an instance, you have to prefix every instance-variable access with obj->. I can see how this could get tedious; on the other hand, this is what prevents ivar-vs.-local name conflicts.
  • If you use object controllers that automatically prepare their content, they’ll use alloc and init, bypassing this initializer. I’ve never used the automatic-content-preparation feature, so this doesn’t affect me.
  • It’ll be less than familiar to anybody who hasn’t read this post, and it’s certainly a change from currently-typical Cocoa code.
  • Doing this in a subclass of a class that has an unusual designated initializer, such as NSView with its initWithFrame:, could get tricky.

My opinion is mixed. On the one hand, real problems with the init way of doing things are rare for anyone who knows the ropes. On the other hand, it sure is more straightforward, isn’t it?

What do you think?

* Presumably the same one most of us recognize as John C. Randolph, although there’s no direct evidence of this on his SO profile.

CocoaHeads Lake Forest videos

Monday, January 18th, 2010

It’s been in editing for over a month, but now, it’s finally done. I’ve just uploaded the second part of last month’s meeting of CocoaHeads Lake Forest. There’s one more to go from last month, and then I can start posting the video from this month.

This one’s a lot more random than the first one. Portions of my own presentation are only part of what you’ll see in this video.

More long-term, I’ve created a channel on Vimeo for all past and future CocoaHeads LF videos.

Warnings I turn on, and why

Saturday, November 7th, 2009

I’ve started turning on most of Xcode’s warning options and one warning-related build setting in all of my personal projects. I suggest you do the same.

ADDED 2013-09-27: The easiest way to do this nowadays is to use this xcconfig file, which turns all of the settings described here on at once.

There are some warnings I don’t turn on, for any of several reasons:

  • They’re inapplicable. For example, “‘Effective C++’ Violations” doesn’t apply to me, because I don’t write C++ code.
  • They don’t help anything. An example is “Four Character Literals”, which is about 'abcd' literals for four-byte-code types such as OSType. These sacrifice something convenient for no benefit, so I leave them off.
  • They are impossible for me to fix. An example is “Multiple Definition Types for Selector”. Cocoa raises that one all over its headers, and I can’t do anything about Cocoa.

The rest of the warnings, I turn on because either they make something clearer or they tell me about either real or potential (i.e., future real) bugs. They are:

  • Check Switch Statements

    Warn whenever a switch statement has an index of enumeral type and lacks a case for one or more of the named codes of that enumeration. The presence of a default label prevents this warning.

    Leave no case unhandled.

    Consider whether a default: label is appropriate for your enumeration. If your switch statement handles all possible values, cut out the default and assert that the value is one of the possible ones instead. An easy way to do this, if the enumeration values are serial and the enumeration is not part of an API you expose, is to have one extra name defined as the number of possible values:

    enum Foo {
    	kFooFoo,
    	kFooBar,
    	kFooBaz,
    	kFooNumberOfValidFooValues
    };
    

    Then, in your assertion macro, compare the value against that name:

    #define MyParameterAssertValidFoo(foo) \
    	NSAssert1((foo) < kFooNumberOfValidFooValues, @"Invalid Foo value: %d", (foo));

    When you add kFooQux, insert it above kFooNumberOfValidFooValues, and the value of kFooNumberOfValidFooValues will increase by one to fit it.

    The result is that your switch statement covers all known values for the enumeration (or you get a warning because it doesn't), and your method throws an exception (from the assertion) whenever anyone passes an unknown value.

  • Hidden Local Variables

    Warn whenever a local variable shadows another local variable, parameter or global variable or whenever a built-in function is shadowed.

    One common way to get this warning is to name a variable index, because there is a function by that name in the standard C library. That's not as much of a false positive as you may think: If you fail to declare your index variable, all your references to it will actually refer to the index function. You can see how it would be bad to send a message such as [myArray objectAtIndex:index] with this bug.

    The solution is simple: Never, ever name a variable index.

  • Implicit Conversion to 32 Bit Type

    Warn if a value is implicitly converted from a 64 bit type to a 32 bit type.

    This is most useful when converting old code to work correctly in a 64-bit architecture. Storing a pointer into an int variable (such as a reference constant) when targeting an LP64 architecture is a good way to get this warning, and rightly so.

  • Initializer Not Fully Bracketed

    Example, Here initializer for a is not fully bracketed, but that for b is fully bracketed.

    	int a[2][2] = { 0, 1, 2, 3 };
    	int b[2][2] = { { 0, 1 }, { 2, 3 } };

    This is a cleanliness warning. It also applies to structures, such as NSRect:

    NSRect warns = { 0.0f, 0.0f, 640.0f, 480.0f };
    NSRect doesNotWarn = { { 0.0f, 0.0f }, { 640.0f, 480.0f } };

    (In real code, I'm more likely to use NSZeroPoint instead of the { 0.0f, 0.0f } element above. It's harder to spell that wrong and get away with it than it is to get away with typing 9.9f, 1.1f, or 2.2f instead of 0.0f.)

  • Mismatched Return Type

    Causes warnings to be emitted when a function with a defined return type (not void) contains a return statement without a return-value. Also emits a warning when a function is defined without specifying a return type.

  • Missing Braces and Parentheses

    Warn if parentheses are omitted in certain contexts, such as when there is an assignment in a context where a truth value is expected, or when operators are nested whose precedence people often get confused about.

    Also warn about constructions where there may be confusion to which if statement an else branch belongs. Here is an example of such a case:

    	if (a)
    		if (b)
    			foo ();
    	else
    		bar ();

    In C, every else branch belongs to the innermost possible if statement, which in this example is if (b). This is often not what the programmer expected, as illustrated in the above example by indentation the programmer chose.

    This may appear to be just a cleanliness warning, but as you can see from the example, it can also warn you about code that may not flow the way you expect it to.

  • Missing Fields in Structure Initializers

    Warn if a structure's initializer has some fields missing. For example, the following code would cause such a warning, because "x.h" is implicitly zero:

        struct s { int f, g, h; };
        struct s x = { 3, 4 };

    This option does not warn about designated initializers, so the following modification would not trigger a warning:

        struct s { int f, g, h; };
        struct s x = { .f = 3, .g = 4 };

    I'm not sure why it warns about the former and not the latter, since all the members get initialized in both code examples (C99 §6.7.8 ¶21). If nothing else, this warning is good motivation for you to switch to designated initializers, which make your code more explicit about which members it's initializing.

  • Missing Newline At End Of File

    Another cleanliness warning—this one, about the cleanliness of diffs.

  • Sign Comparison

    Warn when a comparison between signed and unsigned values could produce an incorrect result when the signed value is converted to unsigned.

  • Strict Selector Matching

    Warn if multiple methods with differing argument and/or return types are found for a given selector when attempting to send a message using this selector to a receiver of type "id" or "Class". When this setting is disabled, the compiler will omit such warnings if any differences found are confined to types which share the same size and alignment.

    I don't turn this one on, because it's unnecessary. When the multiple declarations differ significantly (e.g., one method returns an object and the other returns a float), the compiler will raise the warning whether it's turned on or not. When the declarations don't differ significantly (e.g., both methods return an object), the difference won't cause a problem, so you don't need to worry about it.

    So, you should leave this one off.

  • Typecheck Calls to printf/scanf

    Check calls to printf and scanf , etc, to make sure that the arguments supplied have types appropriate to the format string specified, and that the conversions specified in the format string make sense.

    The biggest reason to turn this on is that it checks your use of methods that take a nil-terminated list of arguments:

    NSArray *array = [NSArray arrayWithObjects:@"foo", @"bar"];

    That message should have a nil after the last argument. With this warning turned on, the compiler will point out that I don't.

    The ostensible main reason to turn this on is to have the compiler check your uses of printf and scanf formats. I don't use printf often (and I never use scanf), so that's not so important for me, but when I do, this could come in handy.

    Sadly, it doesn't work on NSLog calls. This has been fixed in Clang as of 2013. Your printf, NSLog, and stringWithFormat calls all get checked (despite the name of the setting not having changed).

  • Undeclared Selector

    Warn if a "@selector(...)" expression referring to an undeclared selector is found. A selector is considered undeclared if no method with that name has been declared before the "@selector(...)" expression, either explicitly in an @interface or @protocol declaration, or implicitly in an @implementation section.

    Another benefit of this warning is that you can use it to get a warning when you pass a wrong key to a KVC, KVO, KVV, or Bindings method. Uli Kusterer has a macro for that.

  • Unused Functions

    Warn whenever a static function is declared but not defined or a non-inline static function is unused.

    Works best with a policy of declaring any function as static that you don't need to be visible elsewhere in your program.

  • Unused Labels

  • Unused Values

  • Unused Variables

    These follow the general rule of “code you don't have is code you don't have to debug”. If you're not using a label, expression statement, or variable, you don't need it, and you will find your code clearer without it.

    You may notice that I don't turn on Unused Parameters. Most times when I trip that warning, it's a callback function or method, so I can't get rid of the argument. Rather than litter my code with bright yellow #pragma unused(foo) directives, I prefer to just turn this one off. (See my rule above about less code being better.)

Once I have turned on all of these warnings and then eradicated them from my code, I turn on two more build settings:

  • Treat Warnings as Errors

    I call this “hardass mode”.

    Remember what I said above: Almost all of these warnings represent real or potential (i.e., future) bugs in my program. Rather than tolerate them, I turn this setting on so that any time I write such a bug, I break the build.

    I haven't been able to turn this on yet in Adium or Growl, although I have turned it on in Adium's Spotlight-importer project. I do, however, turn it on in all of my solo projects.

  • Run Static Analyzer

    Activating this setting will cause Xcode to run the Clang static analysis tool on qualifying source files.

    The Clang Static Analyzer is the find-your-bugs-for-you tool you've heard so much about. This setting makes Xcode run it whenever you build. Thus, every build, you get all those warnings errors and your analysis results.

    Whenever possible, I leave this on; if there's a source file that it takes a long time to analyze (e.g., GrowlPluginController.m), then I turn it off, but only then.

UPDATE 2009-11-22: Jonathan “Wolf” Rentzsch wrote a script to turn on all of these settings in all of the projects you have open.

UPDATE 2009-11-28: Updated the entry on “Typecheck Calls to printf/scanf” after seeing that Jeremy W. Sherman pointed out a much better benefit of it in a comment on a Stack Overflow answer.

UPDATE 2009-12-05: Corrected the discussion of the index problem. You can't use index, or any other function, as a C-array subscript, so the problem only affects higher-level arrays, such as NSArray.

UPDATE 2013-09-27: Added link to xcconfig; updated section on “Typecheck Calls to printf/scanf”.

How not to use UTIs

Tuesday, September 22nd, 2009

John C. Welch has written an article telling you to use UTIs to replace creator codes.

It is wrong.

Daring Fireball, rosscarter.com, and (the most sober of the bunch), TidBITS have all gotten on the “Apple has abandoned creator codes, now we’re screwed, damn you Apple” bandwagon. They’re all right about one thing: Apple has dumped creator codes in Snow.

So before you panic, there’s a replacement mechanism, the UTI, or Universal Type Identifier.

No. Uniform Type Identifiers are a replacement for type codes (and MIME media types, and filename extensions), not for creator codes. There is no replacement for creator codes.

Uniform Type Identifiers are just that: They identify types of data. Using them for anything else is misusing them.

Ideally, Coda should assign an application-specific UTI for CSS files it creates.

No, it should not.

As it turns out, Coda is a UTI-aware application, and according to Coda’s info.plist file, that identifier is com.panic.coda.css.

And that identifier is wrong, because CSS is not Panic’s format.

I use CSSEdit. Currently, it doesn’t declare a UTI, but if they should follow Coda’s example, they should make one up of their own, such as com.macrabbit.cssedit.css. Now we have one type with two names. Which is right?

Suppose I write an application that accepts CSS data. Which UTI do I look for: com.panic.coda.css or com.macrabbit.cssedit.css? Should I look for both of them? What if I find both? What if a third developer releases a CSS editor? Now I have to keep up with the entire population of Mac CSS editors just to accept all the many names for one type.

The right type identifier would be something like org.w3.css or org.w3.cascading-style-sheets, following the rule that the type should be named after whoever controls it. The W3C controls CSS, so its UTI should be named after them. Some other formats, such as PNG, aren’t controlled by anybody, so they go in public.

You might point out public.html and public.xml, as both of those are also controlled by the W3C. Obviously, I disagree that these should be in public.*. But it’s too late to change them now, so we have to put up with them.

Better examples include com.adobe.pdf and com.microsoft.word.doc. In each of these cases, some third party controls the format, so they get the format’s UTI named for them. Notice that Preview does not invent a com.apple.preview.pdf UTI, and TextEdit does not invent a com.apple.textedit.word.doc UTI; they use the UTIs named for the creators and maintainers of those types.

So now we see a problem. All the text-ish files have the same type identifier: com.apple.traditional-mac-plain-text.

Because they are all the same type. And that type is named after Apple because Apple controls that format (in this case, a text encoding).

The Photoshop PNG file is typed as public.png.

There’s no such thing as a “Photoshop PNG” file. PNG is an open format controlled by no-one (or, arguably, the W3C, in which case the type should have been named for them). What you have is a PNG file that you created in Photoshop. That latter detail is irrelevant to its type, which is why HFS had the creator code separate from the type code in the first place.

If there is such a thing as a “Photoshop PNG” file (that is, if Adobe incompatibly extends the PNG format in some way), then they should assign that format its own name (say, com.adobe.png), because it’s a different format.

If you take away the creator code, you’re screwed, because all you have are the extensions.

Exactly why John Gruber, Ross Carter, and Matt Neuberg don’t like the change.

Coda CSS file props:

displayed name:"test.css", 
creator type:"TStu", 
type identifier:"com.apple.traditional-mac-plain-text",

I’m surprised you didn’t notice this. Why isn’t this file’s type identifier com.panic.coda.css?

… why aren’t any of these applications doing the right things? Pages ’09 does. It sets the type for .pages files to “com.apple.iwork.pages.pages”.

Because it’s Apple’s own format specifically for Pages. Again, see also com.microsoft.word.doc.

Unsurprisingly, it doesn’t even have a creator code.

Yeah. Cocoa makes it difficult to apply a creator code to a file and doesn’t do it automatically, so expect most Cocoa apps to not do it.

Even thought the default for the .html extension is BBEdit, the UTI overrode that. When I changed the handler for public.html to BBEdit, then the file opened in BBEdit. That’s exactly the behavior I’d expect, and it matches what you got with Creator Codes.

It matches what you got when you assigned the default handler of a file type, as well. That’s what you did the newer equivalent of.

There never was a way to set which application opened files that had a given creator code. That was what the creator code was for: Determining which application would opened the file.

Yes, Apple did abruptly kill off Creator Codes, however, they’ve been warning about that for some time now.

Sort of. They’ve been warning that they’d kill off the combination of file type codes and creator codes. UTIs are the replacement for file type codes; as I said above, there is none for creator codes.

Now, I know that ‘simple’ is a big fat lie when it comes to application development, however, at some point during the 10.5 lifecycle, all these applications should have been updated to not only support UTIs, but to use them. Instead, they all relied overmuch on FIle Types/Creator Codes …

Actually, it was more common to use filename extensions. See what I said above about the difficulty of assigning file types and creator codes from a Cocoa app. I think that was actually quite rare, simply because filename extensions were so much easier.

… and now that those are gone, well, the OS does what it can with the information it has available.

No, it doesn’t. The creator code information is still available, and the OS ignores it. The OS now only uses type information to determine how to open a given file, except for files that the user has assigned a specific application to.

Oh, and what about when you change a file association in the Finder? Well, unsurprisingly, the Finder cheats. It adds a resource fork to the file with the path to the desired application coded within. … [M]aybe the Finder could start doing the right thing too?

Agreed. I say it should set the file’s creator code.

Incidentally, I tested in Tiger, Leopard, and Snow Leopard, and Finder did this resource trick in all three versions. If the Info window ever did set the file’s creator code, it hasn’t done that for many years.

If the only way to have a unique UTI associated to a file is for that file to use a completely unique file extension, then WHAT THE FUCK GOOD ARE UTIS? Fucking seriously, why the FUCK bother? BBEdit creates TEXT FILES. Does Apple seriously expect that Bare Bones, to properly use UTIs, is going to now create a .bbedittext extension, a .bbedithtml extension, a .bbeditohmyfuckinggodwhatthefuckisgoingon extension, then make you EXPORT to ‘standard’ extensions, just so you can know a file created in BBEdit will open in it?

And now you know why smashing type information and creator/opener information into a single value is a bad thing.

If this is what Apple is pushing, then everyone who signed off on non-settable UTIs is a fucking idiot…

There is no reason why the average user should be able to change the type of a file. If they created an HTML file, it’s an HTML file, and there’s no reason for a user to be able to set it to anything different unless they really know what they’re doing. (I’ve done it, and I’m assuming you have, too. We’re exceptions.)

What you want to do is to change which application opens the HTML file, and that is completely separate from the fact that the file contains HTML.

Variables for clarification

Friday, August 14th, 2009

Before:

if (![newTrackURL isEqualToString:trackURL] || ([newTrackURL hasPrefix:@"http://"] && !([lastPostedDescription isEqualToString:displayString]))) { // this is different from previous notification, or it's a stream and the playing track has changed

After:

BOOL URLChanged = ![trackURL isEqualToString:newTrackURL];
BOOL isStream = [newTrackURL hasPrefix:@"http://"];
BOOL descriptionChanged = ![lastPostedDescription isEqualToString:displayString];
if (URLChanged || (isStream && descriptionChanged)) {

Why remove the comment? Well, I had just changed the code to what you see in the Before example, but I had not changed the comment, and I thought I was ready to commit. I almost committed a stale comment. It’s that easy. Luckily, I caught it in reading the patch before I qfinished it, so I was able to change the comment to what you see above.

Now I have no comment at all, but the code is clear, so I don’t need one. This is an improvement.

Here, have a coupon

Sunday, July 26th, 2009

Voices That Matter: iPhone Developers Conference
October 17th and 18th.

This October 17th and 18th, there’s a conference for iPhone developers in Boston, which the organizers asked me to attend.

The conference is called Voices That Matter: iPhone Developers Conference, and the titular voices include Aaron Hillegass (famous for his book), Erica Sadun (famous and infamous for her jailbreak work and advocacy), Bill Dudney (famous for his book), Stephen Kochan (somewhat famous for his book), Jonathan “Wolf” Rentzsch, Fraser Speirs, and Daniel Jalkut.

As most of you know, I’m not an iPhone developer—I write for the Mac only. So I declined that part of the offer.

The other part was a coupon for you, my readers. I know many of you probably are iPhone developers, so I asked whether they would still like me to give you that coupon code. They agreed, so here it is:

PHBLOG

(Those of you who read Jesper’s weblog may recognize it.)

Without the coupon, the registration fee is $495 until September 12th, $695 thereafter. The Word document they sent me says that that the coupon will knock $100 off.

Enjoy the conference!

My documentation viewer

Wednesday, July 15th, 2009

This is what I use to view Apple’s documentation:

My web browser.
QuickTime/H.264, 960×538, 1.3 MiB

The application is OmniWeb. I have a series of entry points bookmarked in the (hidden) Favorites bar:

(Someday, Carbon will perish from the list, the ones after it will move up, and another framework—probably either QTKit or Core Animation—will become the new ⌘8.)

And yes, those are all file: links.* Your web browser is perfectly capable of displaying web pages stored locally, and that’s all the Apple documentation is: locally-stored web pages.

With this arrangement, I can get to the reference information I’m looking for faster, and I can have multiple references (even multiple definitions) open at once because OmniWeb supports tabbed browsing.

Here are some other pages worth bookmarking:

You can use these and other bookmarks with a nice feature of OmniWeb which has also, more recently, appeared in Google Chrome: You can type any substrings from your bookmarks’ names and URLs into the address bar, separated by whitespace, and it will know what you mean. So, for example, I can type “kt kit”, and OmniWeb knows I mean “QuickTime Kit”; I simply hit return, and it takes me to that framework reference.

UPDATE 2009-09-07: Updated links to Snow Leopard’s docset name (where possible).

* On Leopard, change the docset name to com.apple.ADC_Reference_Library.CoreReference.docset.

Singletons in Cocoa: Doing them wrong

Wednesday, June 17th, 2009

UPDATE 2010-09-04: I wrote this post about an older version of Apple’s singleton example. The current version is much better: It still doesn’t handle over-releases the way I would like, but there’s nothing objectively wrong with it. As such, there’s nothing wrong with using Apple’s current example. You can continue reading this post to see my criticism of Apple’s old singleton example and my own implementation.


A singleton is a simple concept: It’s an object that you can only have one of. Being that simple, you may think it’s hard to get wrong.

If you do, I welcome you to the wonderful world of programming.

The Cocoa Fundamentals Guide is necessary reading for all Cocoa programmers. Even so, nobody’s perfect, and the CFG’s authors are no exception.

On Twitter last night, a mistake of theirs came to light when someone named Nick tweeted about how hard it is to make a singleton in Cocoa. Nick cited an example from the CFG; Chris Hanson responded that “that example does WAY too much work”, and Bill Bumgarner added that the example is “ridiculous”. They‘re were both right.

Doing it wrong.

The example, in order to “ensure singleton behavior”, overrides four basic Foundation methods:

  • retain
  • release
  • autorelease
  • retainCount

In the override implementations, retain, release, and autorelease are all no-ops. release does exactly nothing; the other two do nothing but return self. The override implementation of retainCount unconditionally returns UINT_MAX.

Before I proceed any further, I’ll give you a caution about singletons. You generally do not need to make your object a singleton at all. Even if your application has a single-window interface, with only one of each controller, you probably don’t need to enforce that. Just don’t create more than one. Then, if you do create more than one, you have a bug.

Let’s digress for a moment. Imagine if you allowed it. Imagine that you allow, say, your app delegate to create more than one of your root controller object. Your app delegate will then proceed to set up both twin objects, and they both respond to such things as notifications.

Bad, right? Now let’s say you “fix” this by making your root controller a singleton.

Your app delegate is still trying to create two root controllers. It’s still trying to set up two root controllers, and as a result of the two set-up messages, the controller is signed up twice for notifications.

But now you really only have one root controller. Your app delegate creates the first one, then gets it again when it tries to create the second. All according to plan so far. Then your app delegate sets up the first object—and then it sets it up again, again thinking that it’s talking to a second object. Even worse, because the object is now signed up twice for notifications (once per set-up message), every notification response happens twice.

You now have only one root controller, but you didn’t fix the bug, which wasn’t in the controller at all, but in the app delegate. To fix the bug, you must fix the app delegate; you don’t need a singleton for this at all.

OK, digression over. Singletons are bad. Avoid them. If you have a lot of them, rip most of them out. (Dave Dribin has bookmarked a lot of other good cases against singletons, and BJ Homer points out that they aren’t all bad. More on BJ’s post later.)

Back to the singleton at hand.

First, let’s look at retainCount. A comment explains that UINT_MAX “denotes an object that cannot be released”, implying that the framework itself considers UINT_MAX a special value.

This is actually correct, although I originally thought (and wrote, in an earlier version of this post) that it was bogus. The documentation for retainCount explicitly says that objects whose release method does nothing should return UINT_MAX.

Next on the hit list: autorelease. This is just mostly pointless. autorelease means nothing more than “send this a release message later”. If release does nothing, then autorelease becomes “do nothing later”. All this override does is move the nothing up to now. A performance optimization, perhaps, but I’d say it’s premature.

And now we come to the real villains: retain and release.

First off, you shouldn’t retain a singleton anyway. I can’t imagine why you would do this, except incidentally, by making it a timer target or something.

But even if you do think of a reason to retain a singleton, you still need to balance retain and release. If you retain without releasing afterward, you are under-releasing the object. If you release without retaining previously, you are over-releasing the object. These two statements have no exceptions.

If you break retain and release, then you’re able to over-retain or over-release (or even both!) the object with impunity. Your app no longer crashes, but you didn’t really fix the problem; you’re just getting away with it. You’re still trying to over-retain and/or over-release an object.

The Cocoa Fundamentals Guide’s primary audience is new Cocoa developers. Those who have never used a retain-counting system before may very well over-release the singleton, and Apple’s example singleton implementation hides that bug from them. That’s bad; every Cocoa programmer should know how to recognize an over-release crash, and breaking retain and release denies the reader an opportunity to learn that. I’ve filed a documentation bug report about the example.

Also, a rebuttal

BJ Homer responds at a different angle to last night’s flurry of tweets.

First, though, we need to get a definition straight. A singleton is a class of which there should only be one instance in any given process. There are actually very few singleton classes in the Cocoa framework including NSDocumentController and NSFontManager. You cannot create more than one of these objects; …

This is true. A singleton object is an object that your app can only have one of. There are a couple of different ways to do this:

… if you try to call [[NSDocumentController alloc] init], you’ll get back the exact same object as you do when you call [NSDocument sharedDocumentController], no matter how many times you call alloc and init. NSApplication is arguably a singleton as well; you can alloc another one, but you’ll get an assertion failure when you call init.

Another way is to simply implement the sharedFramistan method, and leave allocWithZone: and init alone. I suspect that this is common, since it’s the easiest way, but BJ is right that it isn’t a true singleton, since it allows multiple instances.

Where BJ goes wrong is in his defense of the retain and release overrides:

Consider the following example:

MyFloozit *floozit1 = [[MyFloozit alloc] init];
[floozit1 doSomething];
[floozit1 release];

MyFloozit *floozit2 = [[MyFloozit alloc] init]; // MyFloozit is a singleton, so this should be the same object as floozit1
[floozit2 doSomething]; // CRASH HERE
[floozit2 release];

We’ll leave aside the problem that you probably should be using sharedFloozit to obtain the singleton instance of MyFloozit.

When floozit1 is set, a new MyFloozit is allocated, and a static MyFloozit pointer is set. When floozit1 is released, that static pointer is still pointing to the old instance. As a result, when we try to set floozit2 (or when anyone else tries to call [MyFloozit sharedFloozit]), we get back a pointer to that same instance. The one that has been dealloc-ed.

BJ is missing something else the CFG says, which he even quoted later on:

Situations could arise where you want a singleton instance (created and controlled by the class factory method) but also have the ability to create other instances as needed through allocation and initialization. …

(Emphasis added by me.)

A singleton object owns itself. As such, it retains itself. As such, it should never die, because it always has at least one owner—and that’s without breaking retain and release. If it does die, it’s because something over-released it; later, something that was using it will crash, which lets you know that you have a bug. This is a good thing, because now you can fix the bug.

Each of the release messages in BJ’s example balances an alloc message above it. That alloc message may actually return an existing object, but we’re expecting to own a new object. Therefore, the singleton’s allocWithZone: should implicitly retain the existing object.

There is no good reason to override retain and release. Don’t do it. This also goes for autorelease. And, since you never override release, you also never need to override retainCount.

Doing it right

So, having thoroughly dismantled the [old] Apple documentation’s poor implementation of a singleton, let’s look at the correct way to do it.

Let’s go through the requirements:

  • The One True Instance is the only instance. (If you deliberately allow multiple instances, I call this a “multipleton”. I’ll leave that as an exercise for the reader, and concentrate on the true singleton here.)
  • There is a sharedFramistan method. It tests whether the One True Instance exists; if not, it creates the object and remembers it in file-scope static storage. Then it returns the One True Instance.
  • We’ll allow going through alloc and init, and return the same instance. We’ll do this in allocWithZone:, as Apple did. We’ll also need to make sure init doesn’t do its work twice on the same object.

[UPDATE 2010-09-04: I used to have the code inline in the post here; I have since moved it to a Mercurial repository on Bitbucket. You can download PRHEmptySingleton.h and .m from there.]

This is actually even more complex than Apple’s example, but it passes all six of these tests:

  1. sharedFramistan always returns the same object.
  2. alloc/init always produce the same object (which, itself, is the same object as sharedFramistan).
  3. alloc/init will not return an object confused by multiple init messages.
  4. Over-releasing causes a crash.
  5. Keeping alloc/allocWithZone:/retain balanced with release never causes a crash.
  6. If [super init] returns a different object, alloc/init won’t break.

Apple’s [old] example fails test 4. BJ doesn’t show an implementation for his example, but according to his own description of its behavior, it fails test 5. My version passes all six.

Take-aways

Hiding bugs is bad. Even worse is giving code that can hide a bug to new Cocoa programmers who could really use practice in detecting and fixing that kind of bug.

If you really need to implement a singleton, there is a right way to do it. The way currently shown in the Cocoa Fundamentals Guide isn’t it.

Don’t change the behavior of retain, release, retainCount, or autorelease. Ever.

UPDATE 2009-09-04: Removed hasInited instance variable after Christiaan Hofman pointed out its redundancy in the comments.

UPDATE 2009-09-19: Moved assignment of the sharedInstance static variable from +initialize to -init, as suggested by Uli Kusterer.

UPDATE 2010-09-04: Replaced inline code sample with links to the Mercurial repository for the sample.

Don’t pass objects as context pointers

Friday, April 3rd, 2009

Cocoa has several functions and methods that run a panel (usually as a sheet) asynchronously. These functions and methods take a target object, a selector, and a context pointer, and when they finish, they send a message to the target with that selector, passing that context pointer.

A common practice is to pass an object in the context pointer. You retain the object before you call the run-panel function or method, then release it in your callback. For example:

    NSBeginAlertSheet(/*title*/ NSLocalizedStringFromTableInBundle(@"Update Available", nil, bundle, @""),
                      ⋮
                      /*modalDelegate*/ self,
                      /*didEndSelector*/ NULL,
                      /*didDismissSelector*/ @selector(downloadSelector:returnCode:contextInfo:),
                      /*contextInfo*/ (void *)downloadURL,
                      …);

In this example, downloadURL is a local variable, and the object in it was retained above, or maybe not autoreleased in the first place. The downloadSelector:returnCode:contextInfo: method will cast the context pointer back to an object type, probably do something with it, then release it.

This has recently become a visible problem because of the Clang Static Analyzer. The analyzer doesn’t know that NSBeginAlertSheet will retain the object, so it flags this call as a leak. This is the most-often-cited example of the checker’s “false positives”: things that it flags as bugs but that aren’t really bugs.

But is it really not a bug? Is it really appropriate to use an object as a context pointer?

Let’s think about what we’re doing here:

  1. The panel doesn’t know the context pointer is really an object, so it doesn’t retain it. To compensate for this, we’re retaining an object on behalf of another object (the panel). This alone should make you feel dirty.

  2. The panel doesn’t know the context pointer is really an object, so it won’t release the object, either. This is particularly a problem if something releases the panel (quite possible in the case of, say, an NSAlert instance). Then it really is a leak.

  3. If we get released (and, hopefully, take the panel with us or at least cancel it), then we leak the object, because we are only expecting to have to release it (or even to have access to it!) in the callback.

Passing objects through context pointers is an anti-pattern. I hope the Clang Static Analyzer developers never remove this warning, because this is not a false bug—it is a real bug that we should all fix in our programs.

Solutions

That object needs to go in an instance variable somewhere.

The lightweight solution is to create an instance variable on the object that is running the sheet. You store the object in the instance variable when you run the sheet (and leave the context pointer NULL), then retrieve the object from the instance variable in your callback. You’ll still need to retain it when putting it in, and release it both in your callback and in dealloc—those aspects don’t change.

I can hear you saying that this is a waste of an instance variable. What are they, rationed? There’s nothing to waste; instance variables are cheap. And leaking objects is far more of a waste of memory than adding an instance variable.

But this isn’t the only solution.

Another way is to create your own subclass of the panel class (NSOpenPanel, NSSavePanel, or NSAlert), and give the subclass a property you can use instead of the context pointer. You could make it abstract (making the property similar to NSMenuItem’s representedObject, nothing more), or make it specific to your application. The former approach is simpler, whereas the latter gives you a base on which to build a more-customized alert if you later decide you want one. It’s up to you.

The advantage of this solution is that, since you’ve formalized the instance variable as part of a class’s API (and since the instance variable is no longer a bit player but the central part of a class), it’ll be harder for you to forget to manage your ownership of it correctly. Memory problems solved.

One way or another, though, you need to put that object into an instance variable somewhere to avoid leaking memory, feeling dirty, and having the Clang Static Analyzer chew you out.

(And yes, all this applies with garbage collection as well. See the section “GC Gotchas” in episode 36 of Late Night Cocoa, but I disagree with Andre Pang’s recommendation of CFRetain and CFRelease; the right solution is not to dip into Core Foundation, but to avoid the context pointer altogether and use an instance variable instead.)

My CocoaHeads unit testing presentation

Monday, January 5th, 2009

One of the things that’s been keeping me busy lately (too busy, in fact, to keep up Framework Friday and Manpage Monday—sorry about that, and I’ll get back to them when I can) is preparing a video based on the presentation I gave at CocoaHeads last month.

I have now finished it. Its title is simply “Unit testing”.

The subject is unit testing for applications written in Cocoa to run on the Mac. I’m not an iPhone developer, so the video is only generally applicable to iPhone development (as much as it is to any other platform); for specific information about testing on the iPhone, see Colin’s blog post.

I corrected a few things that I got wrong in the original live presentation, and added a few new slides. Other than that, it’s basically the same.

The video is 13+½ minutes long (strangely, about half the length of the original live presentation), and is available in high-definition. You can even download the original file I uploaded, in case you’re so inclined; it uses the lossless Animation codec for the video track, and is 720p and 135.7 MiB.

I used several Creative Commons photographs in the slides. Here are the links back to them:

In other news, I love Keynote’s Instant Alpha feature.

Updates to “How to work with a bound-to array”

Wednesday, December 3rd, 2008

Following an email conversation with Dave Dribin, I’ve updated my earlier post on how to work with a bound-to array.

The most critical update, and the reason for a new blog post to announce the update, is that you should not currently implement addObject: and removeObject: for an array property. KVO has a bug where it treats these as set accessors, even if the property is an array. This will result in crashes if you observe your object using plain KVO.

The workaround is to use indexed accessors:

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

This is a little uglier than addFramistansObject:, but it doesn’t crash.

The other update is that you need to implement both accessors in a pair. For example, for insertObject:inKeyAtIndex: to work, you must also implement removeObjectFromKeyAtIndex: (and vice versa). Otherwise, KVO won’t override the one you did implement, so you won’t get notifications for it.

I’ve filed bugs for both of these, and I’ve linked to both bugs from the older post.

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

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.

Multiple methods found

Friday, March 14th, 2008

I wrote some code like this:

[[QTMovie movieNamed:sound error:NULL] play];

and Xcode gave me three warnings:

  • GrowlApplicationController.m:537: warning: multiple methods named ‘-play’ found

    • /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSSound.h:47: warning: using ‘-(BOOL)play
    • /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/QTKit.framework/Headers/QTMovie.h:340: warning: also found ‘-(void)play

All warnings are bad, but these are even worse: The compiler is telling me that it’s picked the wrong method. I’m creating a QTMovie, so I want it to use -[QTMovie play] (the one that returns void), but it picked -[NSSound play] (the one that returns BOOL).

Now, in this case, it won’t matter, thanks to Obj-C’s dynamism—all it will do is send a play message to the object, and the object will use whatever play method it knows about. In other words, despite what the compiler is telling me, the program will actually call the correct method (the one in QTMovie).

But this could be a lot worse. If I’m expecting, say, a structure type, and the compiler picks a method that returns a scalar type such as int or float (or vice versa), the compiler will write the wrong assembly code for the message. My method will get gibberish back from the method it called, and Bad Things will follow.

The reason for this  problem is that +movieNamed:error: returns an id—not a QTMovie * specifically. For all the compiler knows, that method returns an NSSound *, or even an NSUserDefaultsController *.

Since the compiler doesn’t know what type the method returns, it must pick one from all the methods by that name that it knows about. You can’t rely on it picking any particular one, and I could only guess as to how it makes its choice. For all I know, it’s blind chance.

The ugly and naïve solution would be to tell the compiler what type we’re expecting by casting it:

[(QTMovie *)[QTMovie movieNamed:sound error:NULL] play];

Of course, besides being ugly, this specific code still has the problem of not accepting an error object. What I should do, and will do, is accept the error object and stash the returned movie in a variable, so that I can test it and then either report the error or play the movie.

NSError *error = nil;
QTMovie *movie = [QTMovie movieNamed:soundName error:&error];
if (movie)
    [movie play];
else
    [NSApp presentError:error];

This code is longer, but it will always use the correct method and it doesn’t ignore the error. (You may also have noticed that I change the previously-misleading name of the name variable from sound to soundName.)

Weirdest compiler warning I’ve ever seen

Saturday, February 9th, 2008

Here’s the code:

[[GrowlApplicationController sharedController] setQuitAfterOpen:YES];

And here’s the warning:

Core/Source/GrowlApplicationBridgePathway.m:43: warning: ‘GrowlPreferencesController’ may not respond to ‘-setQuitAfterOpen:’

Wait, what? I said GrowlApplicationController, not GrowlPreferencesController!

The problem is that the compiler is recognizing “sharedController” as a class method, and assuming that I’m using the class that it knows has it—which, in this case, is GrowlPreferencesController. GrowlPreferencesController is declared in its header, which is imported by the prefix header; GrowlApplicationController, meanwhile, is declared only with @class (in another header). So I think it’s assuming that GrowlApplicationController is a subclass or something.

However, +[GrowlPreferencesController sharedController] is typed as returning a GrowlPreferencesController *, so when I try to call a GrowlApplicationController method on it, it gives me that warning.

The fix is to #import "GrowlApplicationController.h" so that the compiler knows that GrowlApplicationController has a sharedController method of its own.

List process start dates

Friday, February 8th, 2008

I just wrote a test app that prints the name and start-date of every process that the Process Manager will tell it about. Here it is:

File: ListProcessStartDates-r4.tbz

It’s a command-line tool, so you’ll need to run it from a terminal. Alternatively, you could wrap the executable in a service using ThisService, then use the service to insert the listing into a text document.

The code to convert the start-date of each process is ugly: Process Manager provides those dates as numbers of ticks since system startup, and I currently go through NSDate to convert those to numbers of seconds since 1970-01-01. I’m fairly sure that this answer is imprecise.

I’d prefer to get the startup time as a number of ticks since some epoch (probably 1904-01-01), so that I can do a more precise conversion. If you know of a way, please post a comment.

Why ASL?

Sunday, January 20th, 2008

It occurred to me just a few minutes ago that I should have discussed this first. So, I’m retroactively designating this post as the first in the ASL series. (I’m also forging the timestamp—I actually posted this at about 16:44 PST).


Most of us probably use NSLog when we want to log some information:

void NSLog(NSString *format, ...);

Those of us unlucky enough to not have access to Cocoa (e.g., working on a UNIX utility) probably use printf/fprintf instead:

int printf(const char *restrict format, ...);
int fprintf(FILE *restrict file, const char *restrict format, ...);

Both of these are fine, but they lack a couple of things.

First off, they lack any indication of a message’s importance. All messages are just lines in a file (especially with the *printf functions), and they’re all on equal footing.

That problem is solved by syslog(3):

void syslog(int priority, const char *format, ...);

syslog lets you specify any of eight different levels of priority for a message:

  • Emergency
  • Alert
  • Critical
  • Error
  • Warning
  • Notice
  • Info
  • Debug

And that’s great. syslog and the lesser functions NSLog and printf/fprintf have served all of us well for years.

But, for Mac OS X 10.4, Apple said “we can do better”.

And so they created the Apple System Logger.

ASL redefines a “message” to be more than just text. Now, it’s a bundle of key-value pairs—what Cocoa and CF call a dictionary. All the usual properties of a message (including the timestamp, the priority, the process that sent it, and the message itself) are now simply pairs in the dictionary. This is the other thing that NSLog and printf/fprintf lack.

This has two practical benefits:

  1. You can make up your own properties. You’re not limited to just the stock properties anymore; you can invent any properties you want.
  2. You can search the log more easily, now that messages are no longer just text. (This was improved in Leopard, which uses a real database for the log storage; Tiger used a text-based log file.)

And all this is very easy to use—barely more complex than using NSLog. Here’s a taste:

asl_log(NULL, NULL, ASL_LEVEL_NOTICE, "Hello %s!", "world");

I’ll tell more about the task of writing to the log (as well as list all nine of the standard properties) in the next post.

UPDATE 2009-04-24: Corrected use of syslog’s LOG_NOTICE to ASL’s ASL_LEVEL_NOTICE.

How to set up your custom view to work with services

Friday, January 4th, 2008

If you’ve used any Cocoa-based text editors at all, especially TextEdit, then you know that NSTextView provides free support for text-based services. Indeed, this is what makes ThisService so great: there are dozens of programs that work with text at the command line, and those programs are just as useful in the Services menu.

But what if you’re not working with text? What if you’re in, say, an image editor, and you want to insert a screenshot from Grab? (I don’t mean to pick on Acorn; that’s just the situation that gave me the idea for this post.)

This is one of those rare things that you have to write code for. However, like most things in Cocoa, it takes very little code.

I’m going to give you the test app right up front. You should download that now so you can play along at home. It accepts any image, such as from the Grab services.


The first thing you need to do is tell AppKit that you can handle certain types. You’ll do this by implementing this method in one of your NSResponders—probably a custom view:

- (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType

This method will be called a lot, so try not to take too long in this method. Fortunately, your implementation will probably be very simple. Here’s the implementation from the test app:

Here's a diagram showing what “send” and “return” mean in the context of a service.
- (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType {
    if ((sendType == nil || [sendType length] == 0U) && [[NSImage imagePasteboardTypes] containsObject:returnType])
        return self;

    return [super validRequestorForSendType:sendType returnType:returnType];
}

The sendType is the pasteboard type of data that you will send the service (its input), or nil* if it doesn’t take input. The returnType is the pasteboard type of data that the service will return to you (its output), or nil* if it doesn’t give output. In Leopard, they can also be UTIs; you’ll be called with both the pasteboard type and the UTI.

If you can handle that combination of send and return types, then return the object that will handle it. That object, whether it’s self or another object, must conform to the NSServicesRequests protocol.

If you can’t handle that combination of types, call up to super, and return that.

Your return value to this method controls whether the service’s menu item will be enabled or disabled. For this reason, if your custom view allows a selection (such as a range of the view’s text, or a sub-shape of its image), you may want to consider the selection. In particular, you may or may not want to say you can send the service data if the user hasn’t selected anything.

Note: On Leopard, your view must be in the responder chain, or this method will not be called. Thus, you may need to add code for it to become the first responder. If this method doesn’t get sent to any object, or if it does but doesn’t return an object, you don’t get any services.

* In both cases, the documentation says empty, which would be @"", but reality disagrees.


Exchanging data

If you’ll be providing input to the service (such as some text to TextEdit’s “New Window Containing Selection”), then you need to implement this method:

- (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard types:(NSArray *)types

The name is not an accident. The idea is that, if the user can select a portion of the data, this method should consider that selection.

The types array is of pasteboard types (and probably UTIs, on Leopard—but I haven’t tested this part) that the service is ready to accept from you. Don’t panic if you can’t provide all the types; just provide all the types that you can provide efficiently. Then, return YES.

If you can’t provide any of the types in the array, return NO.


If you’ll be receiving output from the service (such as a screenshot from Grab, or a result from a service such as Script Editor’s “Get Result of AppleScript”), then you need to implement this method:

- (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pboard

Replace the currently-selected data with the new data from the pasteboard, then return YES. If there’s no data on it that you can use, return NO.

And an answer: What to do if your table view shows the whole array in every row

Sunday, December 9th, 2007

Before writing my previous post, I had asked some people on IRC for help, including David Smith, who is a fellow Adium developer. He remembered a solution, but uncertainly. One thing he said, though, proved relevant: “You have two NSTableColumns; which one is it [NSTableView] creating the content binding from?”

David was referring to the content binding of NSTableView, which I had dismissed as an artifact of an earlier design of NSTableView, or perhaps a simplified path for those people who had only one column in their table view. (I saw the mention in the docs that the table view binds it automatically to the value of one of its columns’ value bindings, but didn’t make any connections then.)

This latter explanation made the content binding incompatible with my app, since I had two parallel arrays of NSStrings (one array contained keys, and the other contained values). So I continued looking for a solution, and eventually gave up and wrote the post.

After I published it, Scott Anguish posted a comment on it:*

you can’t have simple arrays of strings as the content of an array controller. it doesn’t work. You need to have an array of objects of some sort that have an attribute, even if they’re just NSDictionaries with a single attribute called “string”.

I don’t believe that NSArrayController has a special case for NSString, but Scott’s comment got me thinking. I added a category to NSString that added a -selfString method, then added that name as the model key path in the table columns’ value bindings. I was wondering, you see, whether this would be enough to satisfy NSTableColumn and NSArrayController.

It still didn’t work. At this point, I had the idea to fire up F-Script Anywhere and have a look around. I did that, and was digging down to the table columns when I noticed this:

That’s FSA’s object browser, showing the table view. So the table view’s content binding was bound to the keys array controller, with a model key path of lastMessageKeys.

That’s why the keys were showing up fine—they were in the array that was in the table view’s content binding. The values array was a different array with a different array controller, so NSTableView threw up its hands and simply showed the entire array’s description.

This is the point that Scott came close to: NSTableView expects you to have one array of model objects—no more. My parallel arrays of NSStrings do not qualify, because only one of the array controllers can be the value of the table view’s content binding.

So what role do the columns play? Well, each row in the table view (and by that, I mean *the whole row*) corresponds to one of those model objects. The value in each column is then determined by the model key path in the value binding of the corresponding NSTableColumn.

Thus, all the NSTableColumns’ value bindings must be bound to the same array controller and the same controller key, and each column should be bound to a different model key path. Your columns’ value bindings should look like this:

Column “Foo” Column “Bar”
Bind to: Your one array controller
Controller key: arrangedObjects (or whatever)
Model key path: foo Model key path: bar

In my case, of course, this required creating a new model class for a key-value pair, to replace the parallel arrays of NSStrings. This is a good thing, since it brings conceptual purity to my design. Remember, Cocoa is designed around MVC; I didn’t have enough M in my app, which was the problem.

So, in summary, here’s the fix for an NSTableColumn that shows the entire array in every row:

  1. Replace your evil parallel arrays with a model class, and a single array of instances of that class.
  2. Delete all but one of your array controllers, since you now have only one array. Update the remaining controller’s model key path to point to your new array (I assume you renamed it).
  3. Bind all of the table columns to your new One True Array Controller, distinguishing the columns only by the model key path, which identifies which property you want the column to show for each model object.

Many thanks to both David and Scott for their help in discovering the root of the problem.

* Scott posted his comment on the previous post with no last name; he identified himself in a comment on this post.