Day 8: +drawImageWithSize:block:
I received some comments with regards to my post yesterday from people who didn’t like my approach. After a little conversation it turned out there was a misunderstanding about what these hooks were supposed to do. So let me clarify
When you need to extend your baseclass in some way, the most common approach is to subclass. The problem this introduces is called the ‘fragile base class problem’ and this concern was pointed out by @mikebernardo who voiced his concern that my solution presented the exact same proble. I think my solution with hooks has a few benefits, so let me outline those:
- The main problem in a fragile base class is that ‘seemingly safe modifications to a base class may cause the derived classes to malfunction’. This is because the base class is oblivious to what subclasses are doing and there’s really no way for it to know. In my hooks solution the base class provides an explicit point where categories can do something and this is explicitly stated in the base class itself.
- If this hook needs to be provided in the middle of a method, there’s no clean way to do this in subclasses; if you want to call super in your subclass you have to either first call super and then do your thing or the other way round; you can’t put code in the middle. The other solution is to copy-paste the code from the superclass and insert your method call halfway. Clearly this is a bad solution.
- Lastly, my hooks were never supposed to really change the behaviour of the base class. Instead the idea was to extend it. There is a subtle difference here. The example I gave was for adding KVO and I think that’s a good example of extending rather than changing behaviour.
Anyway, on to today’s post and I bet this one will be less controversial. As you might understand, I do a lot of custom drawing in both DrawIt, Sketch and even in Fontcase. DrawIt is now 10.6 only and that gives me the possibility to use blocks. We already covered blocks a bit, and today I have another example:
+ (NSImage *)drawImageWithSize:(NSSize)aSize block:(BLOCK)block
{
NSImage *image = [[NSImage alloc] initWithSize:aSize];
[image lockFocus];
block();
[image unlockFocus];
return [image autorelease];
}
(Let me state that I’m not happy with the name of the method, but I can’t think of a better one). I supppose the code itself is quite straightforward except ‘BLOCK’ thing on the first line. I’ve declared a BLOCK preprocessor as a convenience here. Most of the blocks I use don’t have any arguments and I dislike their syntax in methods declarations intensely. Hency my preprocessor: #define BLOCK void (^)(). And that’s even a second tip for today, I’m too generous. :-P