Back in the heady days of iOS 2, before NSURLSession, developers had to build their own networking stack. There was a class called NSURLConnection and it had a delegate, the aptly-named NSURLConnectionDelegate.

An object conformed to NSURLConnectionDelegate with a few key methods:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;

While the new NSURLSession APIs are much nicer, these methods gave you a lot of control (mostly control that you didn’t need). They have another quality that I think is somewhat enlightening. This protocol suggests its own implementation.

You can tell by looking at the API that didReceiveResponse will get called once, didReceiveData will get called at least once and maybe even more than once, and connectionDidFinishLoading will get called once as well. didFailWithError might get called once, and you probably won’t get any more callbacks after that one. And since you know that you’re going to have to keep track of some NSMutableData instance variable to glue all of these disparate pieces of data together. With that knowledge, you can put together an implementation:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
	self.receivedData = [NSMutableData data];

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
	[self.receivedData appendData:data];

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
	id object = [NSJSONSerialization JSONObjectWithData:self.receivedData options:0 error:nil];
	//call completion block or delegate

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
	self.error = error
	//call completion block or delegate

(This code is actually from an old app of mine, from around 2011.)

Because you need to keep track of this instance variable, it’s glaringly obvious that you can’t keep it around in a view controller or another high-level object. Every single request that a view controller needed to send would need its own NSMutableData variable. So just by the nature of the design of this API, it almost forces you to create a new object for a request. (This is a pit of success. Make the right way and the easy way line up with each other.)

And so even those of us who were writing huge view controllers knew that it was wrong to keep that kind of data in a view controller, so we made a custom little object for interfacing with a web server. Sometimes that custom object got out of hand and started doing way too much, but that’s a blog post for another day.

Eventually, we all moved on to AFNetworking, which handled all those messy bits for you. But somewhere, deep in the bowels of AFNetworking, there was an object whose primary purpose was to act as this delegate.

While there’s plenty more I could say about the institutional reasons that caused Apple gave us this low-level API instead of something a little simpler to use, I’ve always been more intrigued by the idea of a protocol that gently forces you to create a new object, just by the virtue of its API. What if more protocols pushed you in that direction? What if we took existing protocols and forced ourselves to implement them as wholly new objects?

I want to examine three of these cases.

First, UITableViewDataSource. This is a really common protocol to break out of a view controller. This extraction is a frustrating one, because the table view protocols are somewhat poorly factored. Why is cell height calculation in UITableViewDelegate, whereas cell generation (like cellForRowAtIndexPath:) is in UITableViewDataSource?

Still, it can be a worthwhile object to extract, but remember that the object conforming to this protocol probably should have its own collaborators and child objects.

Second, I want to take a look at UIAlertViewDelegate. Because UIAlertView has been deprecated in favor of UIAlertController, which has a block-based API, this protocol isn’t common anymore. However, we can still learn from it. The protocol suggests making an object whose job it is to present the alert, conform to its delegate, and handle the button taps. Even though the new block-based API doesn’t suggest this implementation in the same way as the protocol-based API did, it’s a smart place to start thinking about breaking out a responsibility. I proposed this in 8 Patterns to Destroy Massive View Controller, as the “Interaction” pattern.

Lastly, I want to talk about UINavigationControllerDelegate. This delegate is a weird one, and I struggled for a long time with this one. Because UINavigationController objects don’t really have a parent, it’s not obvious who should be their delegate. Most of the work they do (pushing and popping) is usually handled by their child view controllers. If a second child view controller in the stack needed access to the delegate of the navigation controller, it could just call self.navigationController.delegate = self in viewDidLoad, and that would work. But then if the third view controller in the stack also needed access to that information, it would take that delegateness away from the second view controller, and the second view controller wouldn’t work as expected anymore.

Traditional navigation-based iOS development has an upside-down view of the app’s control hierarchy. The child (a view controller) grabs hold of the parent (the navigation controller) and tells it how to behave. With the navigation controller having no logical parent, its delegate doesn’t naturally fit in anywhere.

The solution to both of these problems took some time for me to figure out, but it ended up being the kernel of the idea of Coordinators. Coordinators are an object suggested by the idea of a specialized object for a UINavigationControllerDelegate, and as the natural parent for a UINavigationController are the right place for those delegate methods to get fired.

Every object needs a purpose, and conforming to a complex delegate can be one purpose. Next time you see a delegate, ask yourself if it makes sense for this delegate to be its own object. Break it out, and see if you like it.