Having experience with a wide variety of languages and tools can sometimes leave one in a frustrating situation: one knows an easy way to solve a problem using some language or toolset that’s not practical for the target platform. Recently, I was working on an iOS app with a library that generates a stream of data into an NSOutputStream. Seems like a reasonable way to design a library. Without looking closely, one could assume that it would be easy to add some manipulation to the stream of data on its way to a file, resource or memory buffer, perhaps to filter out unnecessary content. The first thing that comes to mind is to create a subclass of NSOutputStream that overrides the write:maxLength: method, but that turns out to be a rather onerous undertaking: it’s easy to overlook the statement in the NSOutputStream documentation: “you may have to implement initializers for the type of stream data supported and suitably reimplement existing initializers.” The compiler doesn’t help, since it sees the initializers declared, so if your subclass (or its client) tries to use any of the initializers other than init, it will compile without any warning but trigger an unrecognized selector exception at runtime. That’s because the subclass of NSOutputStream isn’t “toll-free bridged” to the foundation class that implements those initializers.
One answer to this is to create a subclass that creates a delegate instance of NSOutputStream and implements the desired initializers by implementing all the methods of NSOutputStream as calls to the corresponding method on the delegate. That results in a class with a whole bunch of code (14 overridden methods) with no added value.
So I talked with my colleague, Sanjit Saluja, and he pointed out some code that does message interception. That led us to the idea that instead of creating a true subclass of NSOutputStream, we could create a class that creates objects that contain a delegate instance of NSOutputStream with some short and sweet message forwarding so that these objects act like NSOutputStream. That way, there’s only code to implement the new behavior (as one would expect when specializing a class), plus a couple of methods to tie the new class to delegate.