For pedagogical reasons, could someone tell me what the difference is between the two? And if possible, which one is better?

(As you can probably guess, my very first solution consisted of version 1 with a release, which brought me to the debugger in a hurry.)

The short answer is the difference between the two is that the second one wastes time and memory to no good effect. There are several problems with the second one: for example, if you really wanted a immutable copy of a string, you should just use [[inputField stringValue] copy] and not -initWithString:, because the latter always allocates a new string, whereas the former will just return the same object with an increased retain count if the original string was already immutable. Now that's fast!

But, in fact, there's no point in doing this copy of the inputField's string, for two reasons. First off, when you call -setStringValue: on outputField it's really the field's job to make sure it holds on to a immutable copy of the string you've passed in, so it's going to call -copy or do something similar itself. (It's true there were bugs in early versions of NeXTstep where sometimes mutable strings would be retained or returned instead of immutable ones, but those are mostly ironed out now.)

Secondly, and more importantly, you're not actually passing this string directly to your output NSTextField, you are generating a new, autoreleased string in your +stringWithFormat: call, which has the inputField's stringValue as a sub-string. Now, leaving aside the actual implementation details of +stringWithFormat:, it's a given that it will somehow keep an immutable copy of any strings you pass into it. Otherwise, honestly, nothing in this damn system would work.

Less code is better if it's functionally the same, and the second implementation is absolutely no safer in any way. Even if you were, say, messing with multiple threads at some point, so the value of inputField could change during your action method, both implementations would be failures, so there's really no conceivable situation in which the second implementation is better.

Also, what's up with that blank line at the beginning of your methods? Seriously, that isn't helping anyone.

Finally, I should point out both implementations are really non-optimal in the post-10.3 world: what you should really do is bind the 'value' inputField to a new instance variable in your controller in Interface Builder (say, NSString *inputString;), and then bind outputField's 'value' to your controller with the path of, say, 'outputString', then write the following:

Admittedly, this isn't really less code, and in fact it change the semantics of your app: eg, it doesn't require you to send the action to populate the outputField. But bindings are generally the way you should code these days; if you find yourself using target/action, or otherwise manually pushing or pulling values to or from controls, think hard about using bindings instead.

15 Comments:

Wil, good post. I am a little (perhaps pleasantly) surprised at your suggestion to use bindings as this example as I have to admit it didn't even occur to me. How often do you advocate doing this? It seems like you're suggesting here pretty never use target/action anymore. Is that true? Are there exceptions? Is that what Apple advocates too? Thanks.

It always astounds me how hard it is for people to really grasp the retain/release/autorelease concept of memory management. I often see people do very weird things just because they think it is cleaner. More often then not they end up doing things like in this post, which really doesn't help at all.

I too am going through Cocoa Programming for Mac OS X by Hillegass. While I agree that bindings is the way to go, it's not covered until a latter chapter (chapter 6 I believe). The first few chapters focuses on target/action.

Enough lurking already... This really took me off guard; using bindings for even the most basic of variables and actions. I set this up as shown and it runs great, so again I'm doubly surprised that something so short can be so mind-bending.

I just started gnawing on bindings and core data this week and I haven't until now seen the method setKeys:triggerChangeNotificationsForDependentKey: ... could you please distinguish between this and bind:toObject:withKeyPath:options:, which I have been using extensively? And here I thought maybe I was doing *something* right.

And if I may: could you expand on how bindings fits into the contemporary Cocoa programmer's toolkit? What I mean is, if your solution to this exercise is really the optimal, then perhaps Cocoa newbies working on that first currency converter ought to be taught how to do it with bindings, from right there onwards. What's more, now when I am going through the docs I can choose to implement a datasource, a delegate, bindings, possibly other tools, and now bindings supposedly replaces target-action as well (to an extent).

Is this a case of the shiny new hammer? Are we better off with so many options for how to solve a problem? If Bindings are the new orange, I would like to see some other whole styles get deprecated, because I for one have made the mistake before of using old techniques and only later finding out that 10.4 extincted the poor sap (NSURLClient protocol, anyone?)