Pick a Delegate… Any Delegate… On Clean View Controllers in Swift

The delegation pattern is ubiquitous in iOS development – the pattern is a “core competency” for developing in Cocoa, and if you program with the iOS SDK for any length of time and you’ll end up writing some code that resembles  someInstance.delegate = someDelegate.

One of the toughest things that I’ve experienced is choosing what someDelegate is.  All too often, a View Controller ends up being assigned the responsibility of being the delegate for everything in its hierarchy.  My question is:  Is there a cleaner way?

Let’s pick up on the example I proposed in my recent post about sending e-mails in-app.  For “quick and dirty” pragmatism, I just crammed everything into the View Controller with the promise of coming back and (hopefully) showing a cleaner way.  Here is a quick link to example posed before if you’d like to review it before proceeding.

What if…

What if we could make some adjustments so that the View Controller was trimmed down to the example on the right (click for larger view):

Clean View Controller Comparison

I’ve created a fully-working example on GitHub if you’d like to download it and play.

So the question at hand:  Is the class labeled “Clean Example” preferable (ie, better)?  First, let’s explore how I accomplished the “clean” View Controller.  Then I’ll tip my hand on and share what I like about this approach…

EmailComposer

In order to accomplish the self-declared Clean View Controller above, I placed all of the configuration processes and the delegate method for the MFMailComposeViewController in a new class called EmailComposer.  It should look familiar if you recall the previous example:

So literally, the only thing I did is

  • Cut the function definitions for configuredMailComposeViewController, and the MFMailComposeViewControllerDelegate method.
  • Paste them into the new EmailComposer  class, which inherits from NSObject  (a requirement for this particular delegate protocol’s conformity), and conforms to the MFMailComposeViewControllerDelegate  protocol.
  • Adjust my View Controller to create an instance of EmailComposer , obtain a configured MFMailComposeViewController, and present it whenever the user taps on a button in my UI.

Conclusions

  • The View Controller in its final version is focused.  It’s primary concern is presentation and handling of user interaction with the View itself, rather than needing to worry with configuring an  MFMailComposeViewController and its delegate callback.
  • EmailComposer is less of a hassle to test, in the sense that I no longer need to instantiate a View Controller in my XCTestCase class just to test my MFMailComposeViewController stuff.  It’s a real pain to test an actual View Controller instance, so I like that I can easily create an instance of EmailComposer and test away without the bulk.
  • No need to import MessageUI in my View Controller.

All in all, this is the cleanest, simplest, most balanced solution (that I could think of) to factoring out some logic to another class, so as to make my View Controller as clean as possible.

The goal was to make sure the appropriate responsibilities are assigned to the right classes.  Presentation logic is all in the View Controller.  Configuration and delegate callback implementation is done in EmailComposer.

I’m thinking through applying this same idea to other more complicated examples (UITableViewDataSource and UITableViewDelegate come to mind), and I think it would do us a lot of good to strategize on how to avoid making the View Controller the “catch-all” delegate / data source class for everything that’s currently on the screen.

Hopefully these thoughts spark some ideas in the Swift community.  This post has already been revised slightly based on feedback that I’ve received from folks on Twitter.  If you have additional ideas in regards to choosing the right delegate, holler my way!  I’d love to hear from you.

Thanks for reading.

  • James Munro

    Interesting article!

    This is a good example of splitting up the table view data source: http://www.objc.io/issue-1/lighter-view-controllers.html
    I didn’t write the article but I’ve applied this approach with good results in a large project – I also created a reusable data source object based around an NSFetchedResultsController to be used with Core Data.

    As an alternative approach to separating concerns, you might like to investigate the VIPER architecture: http://www.objc.io/issue-13/viper.html (although be warned it is quite a departure from the conventional architecture for an iOS app, it does have clear benefits).

    The articles are ObjC but can be easily ported to Swift.

    • Andrew Bancroft

      Hey James!

      It’s great you mentioned Chris’ article on lighter View Controllers. I had previously read his article and even incorporated that pattern into a project I did for work. It worked really great! In fact, I had that exact post in mind when I was thinking through how I’d split out responsibilities for the side project I’m currently working on that required [something] to be a delegate for [something else]. Thanks for sharing that – it’s perfect because in many ways that article was the foundation for me even thinking along the lines of, “This View Controller shouldn’t be responsible for –everything–, should it?” :]

      I’ll have to check out and ponder the VIPER architecture. Even if it’s “different”, it sounds like there could be some benefits to at least knowing it’s something I could know, you know? Have you ever used it or ideas from it?

      I appreciate you sharing, James!

  • Pingback: Send Email In-App – Using MFMailComposeViewController with Swift | Andrew Bancroft()

  • Pingback: Expanded Thoughts on Swift’s Type Inference | Andrew Bancroft()

  • Pingback: Clean Coding in Swift – Functions | Andrew Bancroft()

  • Pingback: Send Text Message In-App – Using MFMessageComposeViewController with Swift | Andrew Bancroft()

  • Pingback: How Delegation Works - A Swift Developer's Guide - Andrew Bancroft()

  • blwinters

    I’ve been developing iOS apps for about 5 months and while I understand the fundamentals of object-oriented programming, I know that my code would benefit from more application of the single responsibility principle. My app has a dozen or so dynamic table views accompanied by a dozen or so static table views (for editing objects), so I’m sure there could be a cleaner structure to all of this if I were a bit more clever.

    One thing that I’ve done is to extract all my UIAlertController functions for deletion confirmations and invalid data alerts to a separate class and then I can just call that function in the view controller and pass in parameters for the alert’s title and message. Something like this:

    import Foundation

    class ValidationAlert {

    let controller:UIViewController

    init (controller:UIViewController) {
    self.controller = controller
    }

    func showAlert (#title:String, message:String) {

    let alertController: UIAlertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)

    let dismissAction: UIAlertAction = UIAlertAction(title: “OK”, style: .Default) { action -> Void in

    }

    alertController.addAction(dismissAction)

    controller.presentViewController(alertController, animated: true, completion: nil)

    }

    }

    //and in the view controller:
    ValidationAlert(controller: self).showAlert(title: “Missing Information”, message: “Please enter a name for this account.”)

  • Naresh

    Hello :)
    i’m trying to show the MmailComposer from a model class as you did above ,but when im trying to asign the delegate for the composer instance XCode was throwing an error,
    Would be great-ful if i could get any suggestions or a solution

    I’m Using XCode 7.2
    i have added MFMailComposeViewControllerDelegate too ,as below to the model class .
    class Constants: NSObject , MFMailComposeViewControllerDelegate{

    /*
    few lines of my code

    */

    }
    Thanks In-Advance .

    • Andrew Bancroft

      Quick question: The code in the image is in the Constants class, correct? It’s interesting, because the only time I get that kind of compiler error is if I remove the MFMailComposeViewControllerDelegate protocol conformance from the Type declaration up at the top…

      • Naresh

        Yeah the code related to MFMailComposeViewController is in model class only,And i added a singleton instance to constants class and using that instance as delegate of MFMailComposeViewController,It’s working now.i’ve posted a screenshot for reference.

        Anyway thanks for the suggestion :)

  • Bielik

    Hello, I don’t know if there is anyone still responding but is there nice way of accessing this view controller from the emailComposer. In the ViewController I have some data I wan’t to use to compose the message. Of course I could just made constructor (init) and pass necessary data through that. But I wonder if there is a different way. Thank you for your help.

    • Andrew Bancroft

      Hey Bielik –

      If you want to get data from your ViewController to the EmailComposer instance, you’d need it to flow in that direction, rather than trying to “reach back” into the ViewController from the EmailComposer instance. I think your suggestion of making an additional init method on the EmailComposer class would be the best strategy for exposing that data dependency to your ViewController.