Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Good Intentions: A Path to Better View Controllers

83231ffaec4a72ef96d26526872961ac?s=47 Jay Thrash
August 25, 2014

Good Intentions: A Path to Better View Controllers

Originally presented at 360iDev in Denver, CO on August 25, 2014

When building iOS apps within the traditional MVC framework, View Controllers unfortunately bear the brunt of being the de facto dumping ground for all manner of disparate functionality. As a result, they are often the biggest and most convoluted files within our iOS projects.

But it doesn’t have to be that way. In this session, we will learn how to unburden our View Controllers by applying the Single Responsibility Principle and delegation through functional Intentions. We’ll find that by adopting the principles of “Lighter” View Controllers our code becomes much more robust to change, yet remains easy to maintain and test.

83231ffaec4a72ef96d26526872961ac?s=128

Jay Thrash

August 25, 2014
Tweet

Transcript

  1. Good Intentions A Path to Building Better ViewControllers Jay Thrash

    @jaythrash ! 360iDev, Denver August 2014
  2. We need to talk…

  3. Model View Controller

  4. Massive View Controller

  5. View Controller Misused

  6. View Controller Mistreated

  7. Delegate (v) Delegate (n)

  8. I need _______________________ a DataSource for this TableView ViewController A

    day in the Life
  9. I need _______________________ data fetched from the server ViewController A

    day in the Life
  10. I need _______________________ someone to validate the form fields ViewController

    A day in the Life
  11. I need _______________________ a CLLocationManagerDelegate ViewController A day in the

    Life
  12. I need _______________________ just one more thing. It’s wafer thin.

    ViewController A day in the Life
  13. It’s too much

  14. It’s too much We can do better

  15. Separation of Concerns Single Responsibility Principal Apply Two Principals

  16. Stores Techniques 3 Delegate(v) the DataSources Intentions

  17. Stores Encapsulates access to external sources of data.

  18. Stores Encapsulates access to external sources of data. Manage Shared

    Resources ➡ Data Loading & Caching ➡ System Resources ➡ Network ➡ Location ➡ Motion Services ➡ Camera
  19. Stores #import <Foundation/Foundation.h> @class MJTLocation; @interface MJTLocationStore : NSObject +

    (MJTLocationStore *)store; - (MJTLocation *)locationById:(NSString*)locationId; @end
  20. Stores #import <Foundation/Foundation.h> @class MJTLocation; @interface MJTLocationStore : NSObject +

    (MJTLocationStore *)store; - (MJTLocation *)locationById:(NSString*)locationId; @end loc = [[MJTLocationStore store] locationById:id];
  21. Stores Candidates for Stores ! ➡Web Services ➡Databases ➡Filesystem ➡Location/Motion

    Services ➡Camera
  22. Delegate the DataSources

  23. “Lighter View Controllers” obj.io Issue #1 ! ➡ Remove UITableViewDataSource

    responsibilities from ViewController ! ➡ Encapsulate into own class Delegate the DataSources
  24. Delegate the DataSources -(id)itemAtIndexPath:(NSIndexPath*)indexPath {} -(NSInteger)numberOfSectionsInTableView:(UITableView *)tv -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    -(UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath Typical DataSource Pattern
  25. Delegate the DataSources -(id)itemAtIndexPath:(NSIndexPath*)indexPath {} ! -(NSInteger)numberOfSectionsInTableView:(UITableView *)tv ! -(NSInteger)tableView:(UITableView

    *)tableView numberOfRowsInSection:(NSInteger)section ! -(UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath Typical DataSource Pattern
  26. Delegate the DataSources DataSource

  27. Backing Store ViewController Delegate the DataSources DataSource

  28. Backing Store ViewController Delegate the DataSources DataSource

  29. Backing Store ViewController Delegate the DataSources DataSource

  30. Backing Store ViewController Delegate the DataSources DataSource @[x, y, z]

  31. Backing Store ViewController Delegate the DataSources DataSource @[x, y, z]

    plist
  32. Backing Store ViewController Delegate the DataSources DataSource @[x, y, z]

    plist CoreData
  33. Backing Store ViewController Delegate the DataSources DataSource @[x, y, z]

    plist CoreData
  34. Delegate the DataSources

  35. Intentions

  36. Intentions UIAlertViewDelegate UITextFieldDelegate UITextFieldDelegate IBOutlets/IBActions

  37. Intentions Intention

  38. Intentions

  39. Intentions Michael ichael-May

  40. Intentions @interface ViewController ()<UITextFieldDelegate> @property (strong, nonatomic) IBOutlet UILabel *translatedNameLabel;

    @property (strong, nonatomic) IBOutlet UITextField *nameTextField; @property (strong, nonatomic) Person *person; @end ViewController
  41. Intentions - (void)viewDidLoad { [super viewDidLoad]; self.person = [[Person alloc]

    init]; [self updateNameLabel]; } -(void)updateNameLabel { self.translatedNameLabel.text = self.person.name; } - (IBAction)convertTapped:(id)sender { self.person.name = self.nameTextField.text.pigLatinizedString; [self updateNameLabel]; } ViewController
  42. Intentions - (void)viewDidLoad { [super viewDidLoad]; self.person = [[Person alloc]

    init]; [self updateNameLabel]; } -(void)updateNameLabel { self.translatedNameLabel.text = self.person.name; } - (IBAction)convertTapped:(id)sender { self.person.name = self.nameTextField.text.pigLatinizedString; [self updateNameLabel]; } ViewController PigLatinIntention
  43. Intentions @interface ViewController ()<UITextFieldDelegate> @property (strong, nonatomic) PersonContainer *personContainer; @end

    - (void)viewDidLoad { [super viewDidLoad]; Person *person = [[Person alloc] init]; self.personContainer.person = person; } ViewController.m
  44. Intentions @interface PigLatinIntention () @property (weak, nonatomic) IBOutlet UITextField *textField;

    @property (weak, nonatomic) IBOutlet UILabel *translatedNameLabel; @property (weak, nonatomic) IBOutlet PersonContainer* personContainer; @end PigLatinIntention.m
  45. Intentions @implementation PigLatinIntention - (IBAction)translate:(id)sender { self.personContainer.person.name = self.textField.text.pigLatinizedString; [self

    updateNameLabel]; } -(void)updateNameLabel { self.translatedNameLabel.text = self.personContainer.person.name; } @end PigLatinIntention.m
  46. Intentions

  47. Intentions

  48. Intentions

  49. Intentions

  50. Intentions

  51. Stores Techniques 3 Delegate(v) the DataSources Intentions

  52. Higher Learning Topics to Google ➡ objc.io - Lighter View

    Controllers
  53. Higher Learning Topics to Google ➡ objc.io - Lighter View

    Controllers ➡ Bendyworks - SRP & iOS ➡ Chris Eidhof - Intentions
  54. Thanks! @jaythrash jay@jaythrash.com http://jaythrash.com/talks