One of the defining characteristics of Cocoa/ObjC is the mixing of checked and dynamic elements in the course of programming.
Ordinarily, it is good to have the compiler validate your messages to objects, and in Objective-C the compiler certainly checks whether a message is known to be understood by a given receiver. Naturally, it can only do this when it has enough information about the receiver, and in cases where it cannot determine whether the object WILL accept a message, it flags a warning.
Compiler validation is a great thing, and therefore it's best to run a 'clean' project - ensuring that the code is written in such a way as to give the compiler a chance to validate calls for you (e.g. no sending messages to something typed as 'id'!).
Yet, Cocoa makes a good deal of use of truly dynamic (runtime) loose associations. These crop up all over the place:
- Passing dictionaries (key-value collections) of attributes/properties to objects
- Key Value Coding (KVC) to address object properties
- Key Value Observing and Key Value Binding to track changes to properties, or link object properties together
Naturally, there can be no compile-time checking of the usage of services that require the passing of keys or the setting/getting of properties in this way. While such patterns are very powerful, they require discipline in use, and _importantly_ excellent documentation in order to know the right values to use dynamically and to make sense of the inevitable errors that crop up at development time (or indeed in production code).
In using Cocoa, there are definitely moments when you are reminded that you are really dealing with a very dynamic language and library. My biggest frustrations arise when some of the dynamic features simply seem to 'error out' (at runtime of course) with only the most oblique messages to suggest a fix. Because the actual problem is often detected deep in the bowels of a framework, the error message is often not particularly well framed for the code you have actually written, and the actual string you have passed in may have been parsed and transformed somewhat in the meantime (for instance a key path). Most of these errors, when they are eventually chased down, are trivial to fix. The problem is how much time it often takes to make a correct diagnosis - though admittedly this improves with experience.
At this time, I am having a frustrating moment with the new Scripting Bridge. I suppose AppleScript is one of the most indirect forms of programming, by its nature. Nonetheless, the errors you get back are often opaque or too general to really infer what is wrong.
I'm trying a simple piece of scripting of Mail through the bridge: just create and mail and send it. As far as I can tell everything is working up until I attempt to add a 'recipient' to the 'recipients' collection of an 'outgoing message'. Then I get a scripting exception, whose textual description is raw Apple Event codes and whose error number is -10000.
My first questions:
- Whose error is "-10000"? Apple Script, the bridge, or Mail? (I assume the latter)
- Where do I find the detail for this error, and will it be specific enough to help me?
I noticed with a previous problem that the laziness of the bridge could mean that it's not the actual line of code that might be the problem, but it could be the property instantiations on the objects I created a while back.
So... I feel a lot of 'flapping around' coming on in order to track this one down, with lots of experimenting and tracing and debugging. As much as I buy the power and productivity of Cocoa in general, it's this sort of diagnostic session that can really subtract from the overall feeling of productive progress.
[Watch this space for an update when I finally figure out who's not liking my code and why!]