NSString+Templating Addendum
A few additional notes on my NSString+Templating category:
-
As both Michael Tsai and Scott Anguish have pointed out, my assertion that primitive types work with the “%@” format string is a bit off (OK, it’s completely wrong!). “%@” is only for objects (it uses an object’s “description” method, which is a lot like Java’s “toString()” if you’re familiar with that), and it definitely doesn’t work with int, double and the like.
It turns out that my confusion was caused by yet another nifty feature I had missed in the key-value coding documentation: the NSObject valueForKey: method automatically wraps its return value in an NSNumber object if the field it is querying is of a primitive type. Thus, in my code, NSString stringWithFormat: is never actually seeing primitive values, but rather NSNumber objects it can easily render.
-
As Jim Roepcke points out, I’m not the first person to have the idea of creating a templating mechanism for Cocoa. As it happens, the venerable MiscKit contains a framework called MiscMerge, which takes my idea and runs with it!
In addition to the conditional branching I proposed in my previous post, MiscMerge implements loops, some convenient constants (such as date), a few commands, and the notion of a “global” dictionary of default values that can be set from the templates themselves.
It’s a fairly impressive package, all in all, but after taking a look at it, I still think NSString+Templating has a reason to exist: namely, it’s simple! I had considered the idea of using an NSDictionary as a lookup table for tag replacement values, as MiscMerge does, but ultimately rejected it because I didn’t feel like writing the glue code to turn my model objects into into a hash.
The thing I really like about my category is that it acts as a very thin bridge between the model and view (once again, thanks to the awe-inspiring power of the key-value coding pattern!). If you implement your model using proper accessor methods, you’re already most of the way there!
That said, there is one problem with NSString+Templating that MiscMerge handles readily: what I like to call “out-of-band data.” The problem with my approach is that it’s possible that not all of the data needed to fill in the template is contained in every model object. There may be data that is common to every model “item,” and is therefore stored at a higher level in the application. With my approach, there’s no way to get that sort of data included in the merge (short of storing a copy in every model object, which would be dumb).
Definitely something I will have to ponder…
-
I know only mad dogs and Englishmen are still reading this post at this point, but for the benefit of my own memory, I’d like to mention another thing this templating mechanism needs to handle: formatting of data for presentation. It’s entirely possible that users will not want data to go directly into the template, but rather would prefer it to be “cleaned” or otherwise formatted first.
An example would be in code generation, where quotes in string literals need to be escaped. Or in markup languages, where certain characters need to be converted to entities.