Thursday, January 31, 2008

Another discovery... more head scratching

I bumped into NSIndexSet (and its buddy NSMutableIndexSet) today.

It was one of those occasions where I hadn't been particularly aware of a Cocoa class (because it hadn't featured in the guides) until I tripped over it in using another class. In this case I wanted to delete a range of objects from an NSMutableArray, and therefore had need cause to research -removeObjectsAtIndexes:, and lo, there was NSIndexSet.

When I went to read the documentation on NSIndexSet, I became excited that this class was going to nicely fulfill some a requirement that's arisen for a collection of ranges. Indeed, the documentation on NSIndexSet claims that it is implemented efficiently as a set of ranges, and the API makes the right sort of noises.

On closer inspection however, it falls a little short of my needs (at least without work), and I'm left wondering if it was implemented 'just enough' for some pressing needs at Apple, but then left to wither on the vine a little. For instance, I would have liked to have been able to use fast enumeration on the indexes that are set, or better still, obtain objects representing contiguous ranges of indexes in the set. The only way to really query an NSIndexSet to get its contents (as opposed to discrete tests for particular indices), is using -getIndexes:maxCount:inIndexRange. Ouch.

Anyway, NS(Mutable)IndexSet does what you expect it to do when deployed to manage common array index tracking tasks. So, that's fine. It could just so easily have even more utility if adorned with a few more methods.

Wednesday, January 30, 2008

Idle curiosity concerning empty immutable collections

Mutability is an important fundamental that is often ignored by software engineers, and much better software design is often forthcoming when immutability is enforced properly.

Cocoa, very commendably, makes a hard distinction between mutable and immutable objects: e.g. NSString, NSArray, NSDictionary etc. , and one of the things I'd expect is for the empty instances of these classes to be singletons. Indeed NSNull returns a singleton, and in a quick test [NSString string] appears to return the same instance (though this may just generally due to interning/caching: a specific feature of strings). So, I was surprised to find that [NSArray array] yields new instances of empty arrays every time.

This is really no big deal of course, and I'm sure the actual benefits of singleton empty immutable objects is vanishingly small in time or space in any real application, but I was surprised nonetheless to find that the design that led to such a good differentiation between mutable and immutable classes did not go on to include singleton empty instances for these classes.

It's possible there's some historical reason for this choice, or equally likely that it was no 'choice' at all - and the truth is merely that nobody cared enough to do this.

Anyway... back to real life...

Saturday, January 26, 2008

Map and filter with NSArray

Having spent a good deal of my recent professional life getting seriously into (lazy) functional languages, and particularly the implementation of a rather nice (IMHO!) such language for the JVM called CAL, I got to toying with an implementation of map and filter over NSArrays.

OK, this must have been done a gazillion times, but I fancied the mini-challenge anyway (evidently too much hands on my time).

I had no intention of a lazy implementation (too bad), but rather, strict implementations along the lines of Smalltalk/Ruby/... collect and inject methods.

Being a dynamic language, Objective-C can easily handle the dispatching of messages to an object for each element of an array, and I decided to implement an NSArray category to add the requisite collect and inject methods. In Objective-C, to refer dynamically to a runtime method we can use a selector (type SEL). These can be constructed as literals by the compiler with the @selector pseudo function.

Unlike a functional language where the mapping function to perform a single element transform can represent itself (by passing in a function/lambda), in Objective-C will will have to pass a selector and an object that will be the target of the selector (the receiver that will perform a transformation). Languages like Ruby have lambda functions and allow the passing of procedures (Procs). Even Smalltalk, like Ruby, has blocks that can be passed in messages, but for the time being at least (until some generous benefactor adds blocks to Objective-C), we will have to stick to object-selector as the means to reference an element transformer.

So, the most general collect method looks something like this:
- (NSArray *)collect:(SEL)selector on:(id)selObj with:(id)arg2

This asks the containing array, the receiver, to collect the result of sending objects from the array to the 'selector' on 'selObj', where this message also has a extra parameter 'arg2' (beside the array object). The array constructed from all the objects returned is what is passed back.

In practice, quite a few of the transforming methods we might want to call are on the objects in the original array themselves. For instance, if we wanted to upper case all the strings in an array, then the correct method to do this is the -uppercaseString method which all NSString instances will respond to. What this means is that we need a variant of collect that can internally target the object being processed in the source array with the selector invocation. While we're at it, we can add variants of these two methods so far that don't take an extra argument (in case we don't need to provide context to the transformer). That gives 4 variants of collect which would seem to handle all transforming cases, so long as you don't mind bundling all contextual information into the one and only context object that you can send in to the transformer from 'outside', and so long as the transformer you need accepts and returns objects (type id).

Flushed with success, I turned my attention to inject. This method needs to present a selector with each object in turn from the array, together with an 'accumulator' value that is threaded through the entire process i.e. an object that starts off in some original state, and is updated by every call to the selector (which returns the new value of the accumulator). The result of inject is the final state of the accumulator, after all array items have been processed.

The most general prototype of this method is something like this:
- (id)inject:(SEL)selector on:(id)selObj withSeed:(id)accumulator

Once again, we can specialise this in a couple of ways:
1. To use the source array object as the target of the selector
2. To treat the first element of the source array as the seed for the accumulator

Another option could be to include a context object in the design, per the collect example above. I chose not to do this at this time.

Now, the CAL language (like some other functional languages) allows concurrent evaluation of list mapping. Although the former is still lazy, I thought it would be fun to see what it would take to do the same in Objective-C/Cocoa.

The first inclination is that we want to create threads for the various mappings from elements in the source array, to elements (at the same index) in the destination (mutable of course) array. These threads perform the simple tasks of dispatching the source object to a transformer (identified by a selector/object pair as before). Parallel mapping is probably only valuable when the transforming function is relatively process intensive, but in any case, it is an opportunity to spread the cost of transforming all the elements across the available compute resources.

Looking at the options for parallelising these transformations, one soon considers Leopard's new NSOperation. This class, and NSOperationQueue implement a spaces-like pattern, where self-contained task objects are added to a space (the NSOperationQueue), which processing agents (the CPUs) take out and execute using the logic in the operation's own 'main method'. Having never played with these Cocoa classes before, I thought it would be fun to try.

Using NSOperation is easy - particularly if you want to use the basic "non-concurrent" mode (somewhat badly named IMO), which creates the execution context (specifically the thread) for you. It's a simple matter of subclassing NSOperation, creating some private state (ivars) that describe the task - a specification that can be provided when the object is constructed - and a 'main method'. The latter performs the operation using the specification encoded into the instance of the operation.

NSOperations can be started directly (by invoking their -start method), which in the case of the aforementioned "non-concurrent" mode (the behaviour of the default -start in NSOperation) will create a thread and execute -main on it. Thus, you are already provided with some benefit in the NSOperation encapsulation over creating your own NSThread and having it execute some object's method. However, we need some kind of operation controller that will start the right number of operations from an available 'pool', according to the compute resources available (number of CPUs/cores/threads-per-core). This is where NSOperationQueue comes in. Not only can this launch the requisite number of NSOperations to keep all your hardware optimally deployed, but it is a priority queue that is also aware of inter-operation dependencies if these are declared (i.e. an NSOperation can cite other NSOperations that it depends on, and that must be completed before it is allowed to run).

So, to implement a parallel collect, one might envisage a loop through the source array, creating an instance of a subclass of NSOperation (let's call it TransformOp, which is then added to an NSOperationQueue. This should work fine (and in this scenario, there is no need for any fancy prioritisation or dependency management). However, (and perhaps this was just overkill) what I preferred was a way to reduce the number of NSOperationQueues being produced from the array ahead of the those being executed (i.e. some sort of demand pump from the NSOperationQueue that would keep enough operations queued, but reduce the memory pressure of potentially creating thousands of operations for the whole array). Unfortunately, this is not (yet) a feature of NSOperationQueue. However, it occurred to me that you have everything you need to fairly easily create a blocking version of NSOperationQueue to achieve the main goal of reducing the number of operations in existence.

To cause some provider of operations to block on adding a new operation, one can subclass NSOperationQueue and override the -addOperation method. I created a "BlockingOperationQueue" class to do this. In order to do the actual blocking, this subclass maintains a two-state NSConditionLock, where the states are "open for additions" and "closed for additions". The -addOperation method gates the call to the underlying [super addOperation] by having the thread attempt to acquire the lock in the "open for additons" condition. If we're not open for additions, then the thread will block. So much for the gate, who is going to open and close it?

We need to control the state of our gate (condition lock) according to how many operations are currently queued, and some notion of what is 'too much' and 'too little' in the queue. The latter data can be introduced in the form of a 'high water mark' and 'low water mark' number of items. These become properties of the BlockingOperationQueue. A suitable default for these was chosen to be 2 times the maximum number of concurrent operations (available from the superclass) for the low water mark, and 4 times the maximum number of concurrent operations for the high water mark.

Within BlockingOperationQueue, we now need to ascertain when the queue length is changing, and to compare this with the set water marks (setting the condition of the 'gate' when these thresholds are crossed). NSOperationQueue exposes an array of operations currently in the queue, and the documentation informs us that operations is a KVC/KVO compliant key of NSOperationQueue. This means we can safely register for KVO notifications from it to detect when it is changing, which drives the opening and closing of the -addOperation gate.

In summary, the new NSOperation classes in Leopard look to be a very useful addition to the developer's kit. A throttling or demand-based interface to operation providers is a nice addition. Having a parallel map/collect method isn't appropriate for every occasion, but if the transformations are relatively compute-intensive, then can be very useful. As in languages like CAL, this is also a nice way to go about launching parallel activities in general - describing them as a list of items to be worked on, and having parallel computation launched for these items. The downsides in the case of the simple implementation described here are the restrictions in using selectors (one argument and returning an 'id'), and the lack of error handling (though NSError could be deposited as results).

Monday, January 21, 2008

Oooh, NSPredicate functions...

I was looking for a way to manage a set of unique managed objects. Essentially, I needed a heterogenous collection of values whose uniqueness is entirely denoted by their value, without naming or indexing properties. This is set semantics of course, and ordinarily one could rely on -hash and -isEquals defined properly on the objects to ensure their uniqueness in the set. However, with NSManagedObject, you are not permitted to override these methods (they are presumably used to define uniqueness by id in the managed object context). Nothing stops you from defining your own version of isEquals in your subclass however, and this can compare the single attribute payload of one of these objects, with another (using isEquals on the payload objects).

Having achieved that, one can then expect to be able to use -filteredSetUsingPredicate on the to-many relationship (manifesting as an NSMutableSet) defined in the Core Data model for the set of unique objects. However, how does one effect a call to the special equality method in the content objects?

While there's not a whole lot of documentation and examples on the subject (and actually the NSPredicate class reference AND guide are entirely silent on the matter), the NSExpression class reference mentions "Function Expressions", which I stumbled upon while investigating NSExpressions and whether you could use them as a mini expression language aside from their utility in defining predicates.

The documentation for Function Expressions seems to consist of 7 sentences and a single trivial example. However, this was enough to spike my curiosity.

The basic syntax is described as:
FUNCTION(receiver, selectorName, arguments, ...)
...and the target selector is described as having to accept zero or more id arguments and returning an id value.

Thus, my custom isEqualsPayload method could receive its test object as normal, though it would have to deviate from a normal 'isEquals' by returning a BOOL NSNumber instead of the unboxed primitive BOOL.
In the FUNCTION syntax itself (passed to the NSPredicate factory method), my target object is clearly SELF, and the argument object can be passed in the regular format style as a simple %@. I screwed up the selector a few times (too much haste, less speed, and following the simplistic example I forgot to put a colon on the selector name, as my example passes one argument). Several crashes later (yes, NSPredicate seems a little bit keen to die badly if you get this syntax wrong - but I guess that's the price to pay for both dynamic invocation AND a variadic signature) and I had my custom equality method being called - and a nice unique set/relationship. There IS a caveat attached to FUNCTION in the context of Core Data. The reference says (one of the seven sentences!): "Note that although Core Data supports evaluation of the predefined functions, it does not support the evaluation of custom predicate functions in the persistent stores (during a fetch).". I'm hoping that my case does not intersect with the unsupported case (qualified by "during a fetch"), though I'll need to test it with the SQLite persistent store to see if faulting causes a problem. Hopefully however, faulting will occur independently of the execution of this kind of predicate (on the relationship NSMutableSet), and all filtering will occur AFTER the objects have been fully fetched into the set. If not, my implementation (with a relatively small number of objects intended in these sets) might be able to live with a forced fetching of all members of the relationship.

On the subject of uniqueness in Core Data, it would be rather nice if this could be declared somehow. Gating the addition of objects with checks for uniqueness is awkward, though admittedly the semantics of uniqueness could be more complicated than a local (single attribute) test (e.g. via tuples/joins). It's interesting that Core Data does have an 'index' flag on attributes, which got my excited at one point, thinking that maybe this denoted a 'unique key' metadata on the attribute. However, the documentation simply states that this flag is for marking "attributes that might be useful for searching", which indicates a rather less formal meaning.

Friday, January 18, 2008

Travail with scrolling

Had quite the frustrating time with a seemingly simple UI concept over the last few days.

I have some UI (a view hierarchy) consisting of a scrolling single column that shows one tile at each row, but where the row can scroll left/right. These horizontal 'strips' of tiles change depending on the application state, and the number of tiles in a strip typically grows, with the right-most strip representing a 'current object' and all the tiles to the left representing 'historical objects'. What I want to do is scroll the strip to the right-most object (the current one) whenever a new tile appears in the strip.

Now, all the Cocoa binding magic works beautifully, and so does the view hierarchy. The root view is an NSScrollView containing an NSCollectionView set up to have one column and zero rows (meaning "don't care"). The views that populate this column are the 'rows', represented by an NSScrollView containing an NSCollectionView set up to have one row and zero columns. Indicating that a certain area of a particular subview should be scrolled-to by the nearest antecedent NSScollView is trivial: any view can call - scrollRectToVisible: with an area in its own coordinate space, and this message is passed up the view hierarchy to the nearest NSScrollView which attempts to comply. Rather nice. So, I went looking for the where/when I could introduce such a call on my view.

Finding such a place was a little challenging, partly because of what I was trying to do in my code, but partly also because I was looking for a message that gets sent to a view when it has been newly added to a superview and everything has settled down (i.e. the resizing of the NSCollectionView has happened, so the area being requested of the scroller actually exists in its notion of the bounds of the document view). Originally, I thought that -didMoveToSuperview would be a good message, as this might indicate that my new tile was fully integrated into the superview's notion of the world. However, it appears that this message is sent out quite early, and the superview (the NSCollectionView in this case) hasn't had a chance to resize yet.

Then, on advice from the CocoaDev mailing list, I attempted to hook into the frame sizing of the NSCollectionView itself, and use events about it resizing to a scroll to the last tile. The manner in which you have to register with the NSNotificationCenter to get information about your own frame changes seemed a little odd when I approached an implementation. At the moment (!) I don't understand why a view can't override a method to be told about frame and bounds changes, but perhaps there's a reason for having to go about this the 'long way' (maybe the NextStep/Cocoa designers thought they already had a general purpose advisory concept for all, and that should also be what is used for the 'local view'). Anyway, the number of notifications of frame change I'm getting here on an addition of a tile is huge, and that this leads me to wonder whether there's something wrong with my code (more about this in a second...). In the end, I opted for each extant tile view to register for its own frame notifications (assuming that the tile view must be positioned within the NSCollectionView at some point, by definition setting its frame's location). On notification, I test to see if this tile is the 'last tile' and if so, I request a scroll to the bounds of the tile. This seems to work except...

I noticed that the result of the scroll was that the strip was positioned one pixel (or something) too far right, so I could see a tiny portion of the tile to the left of the last one. This looked pretty awful and let me to further wonder whether I still hadn't found the correct place to put my scrolling request. Nevertheless, the scrolling was almost happening right, and I had rechecked that the requested bounds were indeed the current bounds of the tile. Mmmm.

The big question was (assuming I _was_ basically doing the scrolling at the right time): what could cause a rectangle to be incorrect by a small amount (between when I had sampled it from [myTile bounds], and how this would eventually be positioned within the coordinate space of the superview. I resorted to recheck my NIB and here's what I found was that I had some 'Autoresizes subviews' set on some of the views above the tile in the eventual view hierarchy (namely the NSCollectionView representing the strip, and the NSScrollView above this). By turning off the resize flag on the NSCollectionView (figuring tiles in an NSCollectionView are _never_ generally resized), the 'out by one error' disappeared. Flushed with success, I resorted to turning off the "Resizes subviews" flag on the NSScrollView above this, BUT THE PROBLEM REAPPEARED.

At this point, I have fathomed a working set of conditions to get the scrolling to do what I want, but I'm still bothered by a sense that I'm not sure when view hierarchies are supposed to have 'settled down' after the perturbation of having a deep subview added. I clearly need to know when such a point has been attained, and its safe to request a scroll in a coordinate space way down the hierarchy that is highly dependent on all the transforms up the tree.

No doubt I'll work up the energy to research this further when my currently working code decides to be sensitive to some new condition of the application in the future...

Sunday, January 13, 2008

More dynamic coolness... I think

I have a requirement to force the order of some items in my UI according to a property value. These objects being sorted are CoreData NSManagedObjects and, as such, have no formal order - you have to assert this yourself. Binding to a Core Data Managed Object Context from an NSArrayController is a Thing of Beauty, but now I need to assert the order of my objects in the UI. So, naturally, I need to connect the NSArrayController Sort Descriptors binding to a sort descriptor (actually an array of NSSortDescriptors) that will cause the right ordering of its arrangedObjects.

Now, I figure:
1. That I will always want a particular ordering enforced
2. That I don't know where to construct and keep this array of NSSortDescriptors, because this is entirely a UI thing. I could create a property of a reachable object (via NSApplication) that is initialised to this array, but that's not very satisfactory.

It occurs that what I really want to do is to have an instance of the appropriate sort descriptors right there in the NIB - and of course this is exactly what one can do with the Object Inferface Builder component.

But first, I have to arrange to have an instance of an object that IS the right sort descriptor. Without any Interface Builder plugin jiggery-pokery to inject an instance with a particular value set as a property, this is best served by creating a new class that always sets up the appropriate sort descriptor for a particular key and order (e.g. descending).

Forgetting for a moment that what I needed was an array of sort descriptors, I created a subclass of NSSortDescriptor whose -init: sets up the appropriate sort specification. An instance in the NIB was then easily created by dropping in an Object component from the palette, and setting its class to my new class. A binding can easily be made to this object from the relevant NSArrayController in the same NIB.

Then I remembered: "Oops, I need an array of these things, even if it only contains the one sort descriptor object". Mmmm, should I change my class to construct an private NSArray with 'self' as the only element (given that I only wanted the one descriptor and I had made the class a subclass of NSSortDescriptor)? I could then have a property on the object that exposes the array which is what I'd bind to from the NSArrayController. Though, perhaps this shouldn't really be an NSSortDescriptor if I add this allusion of containment?

Another thought occurred. Given the wonders of 'duck typing' I could just have my subclass of NSSortDescriptor masquerade as an array, by implementing -count: and -objectAtIndex: . In which case, -count: would ALWAYS return 1, and -objectAtIndex: would return 'self' for index 0, or raise an NSRangeException otherwise.

I decided, mostly out of curiosity, to try the array masquerading - and this appears to work perfectly.

However, having achieved this, I'm left pondering about best practices. Clearly a lot of Objective-C/Cocoa's dynamic dispatch is to be embraced. Moreover, if one is to fully avail oneself of all the features (including KVO and KVB), then dynamic references via key paths is inevitable. However, there remains a question of appropriate patterns in code you write: it can certainly be misleading for an object instance that advertises itself as being of one class to suddenly know how to behave in entirely different circles. I wonder what the perceived wisdom is in the Cocoa community around such matters (having just arrived myself). Is this just a matter of diligent documentation (and isn't typing almost just a form of documentation in truly dynamic object systems?)

In this particular case, despite the compactness of having a single instance handle what it means to be an NSSortDescriptor (legitimately perhaps making it a subclass of this class) as well as what it means to be an array of exactly one of these objects, it might be considered better form to fully advertise the array qualities, even though they are not really the major concept. More importantly one could argue that even though I currently have no intention of every needing multiple NSSortDescriptors in the array (for primary, secondary, etc. sorting), I may one day need to change that constraint - whereupon it would be much better to have a class that advertises that it returns an array of sort descriptors rather than providing this almost covertly through the happenstance of implementing methods that make the object look like an array to others.

Perhaps I should spend some time looking at best practices where such conundrums have existed for decades: Smalltalk. Although in modern times, I suspect such problems can be better dealt with by the overt documentary power of traits, there must have been many occasions where, like this occasion, there was no protocol to announce "this object has array-like behaviour" despite inheriting from class X. It would be interesting to analyse what choices were made in these situations and which (with hindsight) were considered malodorous!

The many colours of Cocoa drawing

Having used a whole range of drawing libraries over the years, beginning with Digital Research's GEM VDI, through various versions of the Windows GDI, to Java Graphics and later Java2D (Graphics2D), I can attest to the fact that Cocoa's drawing is modern and powerful. Yet at the same time it has a number of surprises (which perhaps derive, as the Cocoa Drawing Guide puts it, from its legacy in NextStep).

I have no experience at all (yet) of directly driving what purports to be the more modern and powerful drawing library on OS X: Quartz 2D.

On first encountering Cocoa drawing (the usual experiments to orientate oneself), one of the things that immediately struck me was the way in which graphical objects express themselves directly into the drawing context. For instance, instead of something like:
[myGraphicsContext setColor:[NSColor blackColor]];
one writes instead:
[[NSColor blackColor] set];

Similarly, true graphical objects like images and paths can simply be told directly to draw themselves into the current graphics context. In Cocoa the current context lives sort of 'in the ether', you do not get passed a context in your drawing method (or obtain/create one ordinarily), and you can issue drawing commands at any time. To target a specific drawable context (such as an image), you simply send the object that contains the target for drawing a 'lockFocus' message. At this point, all drawing done with any graphical object will go to that context until 'unlockFocus' is sent to the same target.

This is quite an interesting inversion to my previous experiences. Indeed, so was the fact that classes such as NSString have an intrinsic ability to draw themselves.

Another oddity is that Cocoa has a set of objects that do know how to draw themselves (paths, strings, images etc.), but some of the more convenient shapes (like rectangles, ellipses etc.) are not available directly. Instead, for convenient drawing of rectangles one uses a family of NS* (e.g. NSRectFill) functions. Drawing rectangles is arguably one of the most common drawing operations, and it's interesting that rectangles are treated so differently (presumably because they are simple and historically NextStep maintained them as simple structs rather than as true objects).

Recently, I had a need to create a hatch pattern: a sort of barber-pole that I could draw over other graphics as a visual cue. As a Cocoa n00b, I thought "OK, I bet there's a nice pattern brush I can set that will be used during fill operations". Hitting the Cocoa Drawing Guide though, I was surprised to find that things aren't so simple. Well... they are and they're not.

It turns out that OS X drawing doesn't support brushes as such. Reading the various porting guides (for Windows developers and Quickdraw developers) pointed to a feature of Quartz 2D, where you can create handlers for drawing 'patterns' programmatically. You simply register a call back, and your routine will be called to fill in pixels in a 'cell' - part of a tiled pattern being drawn. However, further investigation revealed that this feature is not exposed through Cocoa. Instead, Cocoa has a curious (to me) option of creating a patterned NSColor from an image. I suppose it's not that weird when you consider that pattern brushes are just as 'magical' in their effect as a sort of 'magic ink' concept. Anyway,
this colour can then be set into the graphics context as usual with the -set method, and further drawing operations performed. The downside of this approach, at least in my case, is that you have to start with an image, i.e. you either happen to have one lying around with the right pattern and colours/alpha, or you go to the trouble of making an image programmatically and caching it somewhere. As I only wanted a very simple monochromatic seamless texture, the ability to define an appropriate area and be called back to render a single unit/pixel would have been quite convenient. In the end, I opted to launch Photoshop rather than write the code to programmatically create an image (though you could argue that I'd have had to have written essentially the same code if Quartz 2D's programmatic patterns had been available directly in Cocoa).

Having created my pattern colour I was caught out by another n00b error (wrong assumption). I attempted to draw my hatch pattern (complete with fully transparent pixels) over my existing drawing using NSRectFill. This seemed to work great until I moved the window around and realised that the the transparent bits of the pattern were composited in such a way as to make my window transparent in those sections! I wondered whether the "pattern as a colour" thing was fully supported for arbitrary drawing with alpha, and I tried setting various compositing modes into the graphics context to see if that would make a difference - to no avail. Only later did I revisit the documentation on NSRectFill (which I thought I was familiar with!) to discover that it always uses NSCompositeCopy when drawing. Ah ha! By this time I had created code to render a rectangle into an image, and then drawn this in turn into my view, but I was most satisfied to rip all that out in favour of a simple substitute rectangle draw call: NSRectFillUsingOperation

To wind up this somewhat meandering post, I'm sure that I have many more 'ah ha' moments to experience as I continue to get to grips with Cocoa drawing. However, and despite the various asymmetries I perceive in its design, I am beginning to properly develop a _real_ familiarity and trust in how it all works. I'm finding that I need to keep the Cocoa docs pretty close to hand though - probably a little more than I found I needed to do when learning Java2D.

Wednesday, January 9, 2008

A buddy for the last bug?

There seem to be other interactions between AppleScript (Cocoa scripting bridge) and the GC. Specifically, just obtaining the SBApplication object (the first thing one typically does with the scripting bridge in order to talk to another app) appears to fail intermittently with an EXC_BAD_ACCESS when GC is enabled (I'm doing this once every several minutes and holding the reference to the SBApplication object on the stack - so old instances much get collected fairly regularly).

I guess there are still a few rough edges here and there with the GC interacting with various components - hardly surprising when you consider the sheer scale of the changes it induces and how broadly Leopard revamped OS systems, services and libraries to accommodate both GC and 64bit application architectures.

Hopefully we'll see the expected slew of improvements through the wee numbers of 10.5 increments to come (10.5.2, 10.5.3, &c.).

Monday, January 7, 2008

21st Century Errors and Apple Script - redux

OK, it appears to be Apple's bug.

Even the most trivial app exhibits the crashy behaviour (or, at best, the -1700 error about a third of the time).
The problem appears to be with GC. Turn it on (Supported or Required) and you're in Crashville, turn it off and everything is peachy.

Unfortunately (call me a wimp!) there's no way I'd consider working around this issue by converting to a retro non-GC mode for development. I'd like to claim that I've done my time with reference counted memory managers and been let off for good behaviour. In my dotage I rather like the idea of the computer doing something that computers are very good at: keeping track of all the nitty-gritty details of what bits of memory are linked to what and doing the spring cleaning all on its own :-)

Apple bug 5674625 raised, with a simple reproduction case attached (though I bet it's a dup by now - I can't believe there aren't others trying to use NSAppleScript in such a simple way).

Now... maybe I should take the opportunity to learn how to make out-of-proc calls with Cocoa's distributed objects to a little mini-server dedicated to running a single AppleScript contribution and returning the result (or I suppose I could just fork an osascript process!).

21st Century Errors and Apple Script

Playing with NSAppleScript, I'm currently befuddled by -compileAndReturnError returning the following:
{
NSAppleScriptErrorNumber = -1700;
}

Nice.

NSAppleScript.h has no error codes listed, and a search (so far) has turned nothing up.

Actually, about half the time, the particular lines of code (run on the main thread of course, as required by NSAppleScript):

NSDictionary *errors;
[script compileAndReturnError:&errors];

will actually crash the application with the stack:

#0 0x923dfd7c in getDescDataType
#1 0x923e3ad7 in aeCoerceDescInternal
#2 0x923e8075 in AECoerceDesc
#3 0x005ae150 in ComponentCoerceDesc
#4 0x00592bec in ASCompile
#5 0x9600b5bc in CallComponentFunction
#6 0x0058dae2 in AppleScriptComponent
#7 0x005a9927 in AGenericManager::HandleOSACall
#8 0x95fc5ef5 in CallComponentDispatch
#9 0x923cd513 in OSACompile
#10 0x92d84eff in -[NSAppleScript compileAndReturnError:]
...
#23 0x9577692e in NSApplicationMain
#24 0x00002b84 in main at main.m:13

Double nice.

The source with which the script has been initialised has variously been:
"current date"
"beep 2"
and
"tell current application to beep 2"

The opaqueness of the error message, not to mention the intermittent crash, suggests that this one is going to take some attrition to actually chase down. What fun. Watch this space...

Saturday, January 5, 2008

Superstrings and symmetry

Yum.

I like the way I can add local 'special powers' to framework classes such as NSString to extend them to do specific useful things in my app, in keeping with their other more general capabilities.

For example, NSString has methods to create strings from concatenation, or more complex conjoining of components through formating. These are general, naturally. My app required some specific formatting of some strings to make UIDs with variously parseable fields. The methods for this can take specific types for the components, and can perform preflight checks on the validity of these parameters before combining them into the required string image. These methods are specific TO my app, but pretty general WITHIN my app.

So, where should these methods be defined?
- They are essentially pure functions, so should be class methods
- They could be placed on some 'top level' application class as an indicator that they are global to the app
- They could be placed in some kind of 'utility' class, perhaps implying a set of such classes e.g. StringUtils, FileUtils etc.

However, the basic string construction methods are on NSString itself, so wouldn't it be nice to add some methods to this class that are only visible in my app (...Ruby, anyone?). Of course, this is exactly what Objective-C categories allow you to do.

Benefits of doing it the Category way:
1. The formatting methods can be styled exactly like the similar, more general methods on NSString - nice symmetry, and in many ways this has the benefit of being where we expect to find them (though of course you have to include the category to get these additions).
2. We save having to create a slightly naff 'utility class' just to be a home to a few ragbag methods whose only grounding concept is the string.
3. (Compared to something like Ruby)... We get all the proper type checking from the category when calling the class or instance on which the category is defined.

Having said all that, I have no idea about any canon, tradition/religion in the Objective-C or Cocoa community about when and how to use Categories - ergo, whether this is considered de rigueur. However, it seems elegant to me and I'm quite content to make up my own mind on such matters :-)

Friday, January 4, 2008

Apple Event nesting, Mail no likey

Hmm...

My continued experiments in scripting (in this case Mail) have thrown up an interesting issue.
If I get Mail to run an applescript that tells my app about the arrival of some new mail, and then attempt to read this new mail from my application in this call, all sorts of things go wonky.

The most basic failure is that my app fails to 'see' the newly arrived mail when asking Mail. It's as if Mail is not equipped to handle apple events at some times (such as when processing rules), or perhaps this is a more general problem with Apple Events on the Mail process being nested.

The thought had occurred to me while writing the scripting bridge code that it may not be possible to nest an Apple Event connection to a given process inside another connection from that same processes - though I was not able to find any documentation that explicitly told me NOT to do this.

Aside from simply not being able to query Mail as I'd expect, I've experienced a range of other nasties that may be related, including:
1. Apparent lock-ups of my app (but not every time)
2. ...inability to stop the app as a debuggee within XCode
3. ...and (after 2) a full kernel panic

The fix seems to be to avoid the nesting. Simply 'step out of the way' of the original Apple Event from Mail and let it complete before sending any messages the other way on a completely different stack (i.e. 'later').

I'm pretty sure the kernel panic was due to a combination of sitting on a break point while handling the Apple Event from the Mail process, then (possibly after some time-out), attempting to kill the debuggee while some low-level IPC code thought some resources were still being locked between the two processes.

It would seem more likely that the problem I'm experiencing would be an issue with the internal state of Mail at the time it processes mail rules, rather than a general problem nesting Apple Events between processes (which seems rather fundamental for a general IPC mechanism). As a newbie, I need to do some more research...