Blockception

Blocks are a lot of fun and they can make some really slick API’s. It’s also worth noting that blocks also require a fair amount of overhead to get used to how they work and how to use them. I would consider myself fairly competent with blocks but this confidence can lead to potentially “clever code”. “Clever code” is sometimes hard to maintain depending on how clever you was feeling at the time of writing it.

In this post I intend to cover one such bit of “clever code” and how it could be implemented differently to compare and contrast the results.

##Using delegates

I’ll start by looking at the implementation I didn’t actually do and then step by step arrive at the solution I initially wrote. From here I can compare and contrast and see which solution I should have done.

The sequence of events looks something like this

Delegate Implementation

So at this point we have a working solution and all is good.

The code to loop over the points looks something like this

View.m

for (int i = 0; i < self.dataSource.numberOfPoints; i++) {
  CGPoint point = [self.dataSource pointAtIndex:i];
  // convert point and build path
}

Something about asking for the count and then iterating over it seems a little awkward to me, I’d much rather the thing that held this information (the model) kept it’s data a little closer to it’s chest and iterated over itself passing out the points. There are two options here

  1. Implement NSFastEnumeration
  2. Add some kind of enumerator

I prefer the second option

##Block enumeration

The block enumeration ends up looking like this:

Model.m

- (void)enumeratePointsWithBlock:(void (^)(CGPoint point, NSUInteger idx, BOOL *stop))block;
{
  BOOL exitLoop = NO;
  
  for (int i = 0; i < self.locationCount; i++) {
    block(CGPointMake(self.locations[i], self.locations[i]), i, &exitLoop);
    if (exitLoop) {
      break;
    }
  }
}

This creates an issue - for this to work I would have to call this enumerator in the View. I could simply bypass the Controller and pass the View a reference to the Model but I don’t like the sound of this. The more pressing issue is that the Model works in a different coordinate space to the View and the Controller is currently handling this conversion.

To get this to work I’ll need to restructure to look like this

Enumeration Implementation

This diagram actually looks simpler. There’s a couple of things to now note

Straight away I can see a way to remove the requirement to call beginDrawing and commitDrawing at this level by using a block that wraps this up in a tasty sandwich.

##Sandwich block

The sandwich block puts the interesting code that changes as the sandwich filler and the boilerplate as the bread, which will look like this:

Model.m

- (void)drawWithBlock:(void (^)(void))block;
{
  [self beginDrawing];
  block();
  [self commitDrawing];
}

This hides a message in our sequence diagram and removes the requirement to remember to call beginDrawing and commitDrawing.

Sandwich Implementation

So actually getting the View to draw can now all be kicked off from the Controller and would look something like this:

Controller.m

- (void)drawGraph;
{
  [self.view drawWithBlock:^{
    [self.model enumeratePointsWithBlock:^(CGPoint point){
      [self.view buildWithPoint:[self convertPoint:point]];
    }];
  }];
}

Now at this point we can look at the public interfaces of the MVC trio and it’s looking quite smart

Model.m

- (void)enumeratePointsWithBlock:(void (^)(CGPoint point, NSUInteger idx, BOOL *stop))block;

Controller.m

- (void)drawGraph;

View.m

- (void)drawWithBlock:(void (^)(void))block;
- (void)buildWithPoint:(CGPoint)point;

Every object appears to be toeing the MVC line, although I see a method that probably doesn’t belong in the public API. The View now has the method -[View buildWithPoint:], which only makes sense in the context of drawing, it’s not clear by looking at the public interface what this method does or in what context to call it.

So here’s another opportunity to use a block, this final implementation brings us to the title of this post Blockception. We now end up with a block in a block which calls a block passed in by the first block.

This ends up looking like the following:

View.h

typedef void (^draw_point_b)(CGPoint drawPoint);

Controller.m

- (void)drawGraph;
{
  [self.view drawWithBlock:^(draw_point_b drawBlock) {
    [self.model enumeratePointsWithBlock:^(CGPoint point){
      drawBlock([self convertPoint:point]);
    }];
  }];
}

The drawBlock essentially takes the functionality of the old -[View buildWithPoint:] and passes it straight where it is actually needed.

##Differences

###Delegate Implementation

The delegate implementation requires a fair amount more code to write. A @protocol needs to be introduced to allow the view to have a dataSource. There is also the methods on the controller that conform to this protocol and end up proxying them straight onto the Model and then slightly changing the result.

Looking at the initial sequence diagram there seems to be more back and forth of messages to achieve the same result than where we end up.

The Model is required to expose how many elements it has and then allow an external object to iterate over that in a way which is out of it’s control.

###Block Implementation

The block implementation has 2 of my favorite ways to use blocks, which are for enumeration and wrapping code.

The public interfaces for all the objects expose very little about themselves, which is always nice.

There are considerably more awkward carets and curly braces, which can be confusing.

##Conclusion

Looking back at both solutions the delegate technique can be easier to fully grasp and follow along. The block implementation completely failed my “can I explain how this is working to a colleague in one attempt” rule, but I feel the delegate setup would only fair slightly better.

The reason I originally implemented this using blocks over delegates was purely because I had the block enumeration on the Model and this was the only way I could think to make it all fit.

I do like how the block implementation hides away any gory details about the structures of the objects but the very fact that I’ve had to write a blog post about this probably means it’s too clever. I think the answer to “which is better?” is we’ll have to wait and see how the block implementation stands up over time.