Fusing talempong and gamelan with the help of an acoustic drum kit and a custom built Max/MSP patch. This performance is a part of my ‘Applied Performance’ module in Music Technology programme in School of Music, University of Leeds.

He’s a very opinionated man with bold things to say. He has useful insights but sometimes his delivery might be a bit too straight or even harsh for some people.

Two main points that I took from this talk:

  • Don’t structure your classes solely for testability
  • Strive for code clarity, read more code and write more code

Great ‘provocative’ talk from DHH. Worth the watch.

Extending one’s Intention

Leading on from Chris’ Intention post, I continued the journey to make my controllers slimmer.

If you haven’t read the post, please do because the things that I’ll share are based on that. It explains about how to make your controllers as light as possible. So how?

  • Code one and only one functionality as one Intention class
  • Drag an NSObject in the storyboard, make it as the custom Intention class
  • Wire up your controllers to the classes

The fun thing is that you can add features and functionalities in your controller by wiring things up in Storyboard. One can ‘code’ the controller’s functionalities without writing actual codes.

However, I encoutered a problem when working with delegates. An object could only have one delegate object. Delegate objects have compulsory and optional methods that should be implemented in one class that conform to the protocol. Usually each methods has different functionality. If we implement all of them in one class, it will violate the concept of SRP.

I asked Chris himself about the issue, his answer pointed me about multicast delegate.

With a little bit of google research, I found an article and a sample code that explain the techniques involved.

But still, I’m not satisfied. I need a slightly different direction on the implementation. Since using Intention relies so much on storyboard already, I want to able to wire my object to its delegates using Interface Builder rather than using written code. Also, I need all of the delegates’ methods to be called, even for the ones that returns a value.

Take textFieldShouldReturn: for example. The code should traverse all the delegates and check whether it will respond to the method. If it can, then it’s safe to call the method. It should return NO if there’s one delegate that returns NO. Otherwise, it should return YES.

'Proof of Concept' sample app

So here’s how I went with the idea of extending the concept of Intention with delegates. The objective is to be able wire many functionalities as a delegate object.

I made an app to prove that it’s feasible. The app’s pretty trivial. It’s an app with a text field that has three features;

  • dismisses when return key is pressed
  • limits the characters allowed
  • enable a button if the text is a valid email

app screenshot

Controller on a diet (ViewController.m)

The controller in this app is really light. It consists of a text field and an implementation of viewDidAppear:. I need both to make the text field the first responder after the controller appears.

Dismiss On Enter (DismissOnEnterIntention.m)

It’s the same concept as the one in the original post. The only thing that’s different from the original is instead of using textField:shouldChangeCharactersInRange:replacementString:, it uses textFieldShouldReturn:.

Limiting Maximum Character (MaximumCharacterOnEditIntention.m)

The cool thing is that we can set the maximum characters from storyboard with user defined runtime attributes. If not set, then we put a constant with a reasonable value (ex. 30 characters).

max char

Email Validation (EmailValidationOnEditIntention.m)

First, we should have an NSString category for validating email. Next, we need to define how to communicate with external object such as UIButton. I copied the technique from the original post by making an IBOutlet for the target. Make an outlet from this class to the button and set the keypath in user defined runtime attributes.

email target

validation path

Forwarding Delegate Calls (ITNTextField.m)

So how to forward all the delegate calls from a UITextField? The important thing that I learnt from the article is to have all the calls be forwarded to all delegates in the array.

I chose with subclassing instead of creating a separate MulticastDelegate object (like one in the article). I didn’t use forwardInvocation: but I just implemented necessary methods and make sure that all of the delegates is called. One thing to note, we should check first if it responds to the selector before make the actual call.

We need Storyboard to recognize our array of property. We do this by adding IBOutletCollection to our property of delegates. And don’t forget to switch the text field’s class to your subclass (mine is ITNTextField).

Why not use category? In my opinion, subclassing is safer and more proper since we need to add a property1. With this approach, we’re not changing anything with the original UITextField.

Wire Things Up

Check the animation to see how the wires are connected. So we’re adding features only by wiring things. Simple. 👌

wiring

Caveat

One caveat is that IBOutletCollection can’t handle id objects with protocols (ex. id<UITextFieldDelegate>). Since we already defend our code to only call methods from a delegate object that can respond to a selector, then everything should be fine.

Check out the Code

I’ve uploaded to Github for anyone who is interested; extending my intention.

To Sum Up

The concept of separating controller’s code to pieces of intention class could still be improved even more. The class would turn into bits which we can use by wire them up. With this, not only our controller’s code is light, but all of our class still conforms to SRP.


  1. Technically, properties can be added to categories. But I think it’s still cleaner if we don’t touch UIKit classes.