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

Lighter View Controllers

Lighter View Controllers

Mobile Warsaw edition. Including Ultra Light View Controllers.

Transcript

  1. Lighter View Controllers Chris Eidhof Mobile Warsaw

  2. Android People » View Controller 㲗 Activity » Protocol 㲗

    Interface
  3. What is the largest file in your project?

  4. None
  5. ⾠ “My point isn’t that it’s never a good idea

    to break up a large view controller. My point is that it’s worth noticing when it’s not actually helping, when it’s adding complexity - and that it’s worth finding the right balance, which takes some thinking.” Brent Simmons
  6. MVC

  7. Massive View Controller

  8. MVC » Model code in model » View-related code in

    view (or IB) » Webservice in service layer
  9. Model code in model - (void)loadPriorities { NSDate* now =

    [NSDate date]; NSString* formatString = @"startDate <= %@ AND endDate >= %@"; NSPredicate* predicate = [NSPredicate predicateWithFormat:formatString, now, now]; NSSet* priorities = [self.user.priorities filteredSetUsingPredicate:predicate]; self.priorities = [priorities allObjects]; }
  10. Model code in model - (void)loadPriorities { self.priorities = [user

    currentPriorities]; }
  11. MCE Recap

  12. Limit your file size

  13. Pull out methods

  14. Use categories to populate views

  15. Pull out protocols

  16. Pull out protocols » UITableViewDataSource » UICollectionViewDataSource » UITextViewDelegate

  17. #pragma mark UITextFieldDelegate - (BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string { if ([string

    isEqualToString:@"\n"]) { [textField resignFirstResponder]; return NO; } return YES; }
  18. A possible problem This might introduce a lot of extra

    glue code.
  19. Frameworks » Use the frameworks » Child View Controllers »

    View Controller Transitions for state » Optimize your VC for testability
  20. UITableViewController “When the table view is about to appear the

    first time it’s loaded, the table- view controller reloads the table view’s data. It also clears its selection every time the table view is displayed.” UITableViewController Class Reference
  21. UITableViewController “When the table view has appeared, the controller flashes

    the table view’s scroll indicators. The UITableViewController class implements this in the superclass method viewDidAppear:.” UITableViewController Class Reference
  22. UITableViewController “It implements the superclass method setEditing:animated: so that if

    a user taps an Edit|Done button in the navigation bar, the controller toggles the edit mode of the table.” UITableViewController Class Reference
  23. UITableViewController » Clears selection » Flashes scroll indicators » Editing

    behavior » Pull to refresh » Keyboard notifications
  24. However...

  25. None
  26. View Controller Transitions

  27. None
  28. None
  29. Ultra Light View Controllers

  30. Single Responsibility Principle & iOS http://bendyworks.com/geekville/articles/ 2014/2/single-responsibility-principle- ios

  31. The IBAction macro must not be used in a VC

  32. The @interface block in a VC's header file must be

    blank.
  33. A VC may not implement any extra *Delegate or *DataSource

    protocols
  34. A VC may only do work in viewDidLoad, viewDidAppear, viewDidDisappear,

    and in response to an observed change in the model layer.
  35. None
  36. @interface ViewController () <UITextFieldDelegate> @property (weak, nonatomic) IBOutlet UILabel *label;

    @property (weak, nonatomic) IBOutlet UITextField *textField; @property (nonatomic, strong) Person* person; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.person = [Person new]; self.person.name = @"Chris"; [self updateTextField]; } #pragma mark Actions - (IBAction)reverse:(id)sender { self.person.name = self.textField.text.reversedString; [self updateTextField]; } - (IBAction)uppercase:(id)sender { self.person.name = self.textField.text.uppercaseString; [self updateTextField]; } #pragma mark UITextFieldDelegate - (BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string { if ([string isEqualToString:@"\n"]) { [textField resignFirstResponder]; return NO; } return YES; } - (void)updateTextField { self.textField.text = self.person.name; } @end
  37. @interface ViewController () <UITextFieldDelegate> @property (weak, nonatomic) IBOutlet UILabel *label;

    @property (weak, nonatomic) IBOutlet UITextField *textField; @property (nonatomic, strong) Person* person; @end
  38. @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.person = [Person

    new]; self.person.name = @"Chris"; [self updateTextField]; }
  39. #pragma mark Actions - (IBAction)reverse:(id)sender { self.person.name = self.textField.text.reversedString; [self

    updateTextField]; } - (IBAction)uppercase:(id)sender { self.person.name = self.textField.text.uppercaseString; [self updateTextField]; }
  40. #pragma mark UITextFieldDelegate - (BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string { if ([string

    isEqualToString:@"\n"]) { [textField resignFirstResponder]; return NO; } return YES; } - (void)updateTextField { self.textField.text = self.person.name; } @end
  41. Refactor

  42. find . -name '*.m' -exec wc -l {} + |

    sort -n 13 ./Intentions/AppDelegate.m 13 ./Intentions/ModelContainer.m 13 ./Intentions/Person.m 18 ./Intentions/main.m 19 ./Intentions/ViewController.m 22 ./Intentions/NSString+Reverse.m 26 ./Intentions/DismissOnEnterIntention.m 27 ./Intentions/ReverseIntention.m 27 ./Intentions/UppercaseIntention.m 45 ./Intentions/ObserveIntention.m
  43. - (void)viewDidLoad { [super viewDidLoad]; Person *person = [Person new];

    person.name = @"Chris"; self.modelContainer.model = person; }
  44. None
  45. @interface UppercaseIntention () @property (weak) IBOutlet UITextField *textField; @property (weak)

    IBOutlet ModelContainer *modelContainer; @property (copy) NSString *modelKeyPath; @end @implementation UppercaseIntention - (IBAction)capitalize:(id)sender { [self.modelContainer.model setValue:self.textField.text.uppercaseString forKey:self.modelKeyPath]; } @end
  46. None
  47. None
  48. Plan of Attack 1.Put things into separate methods 2.Group the

    methods together 3.Move related methods into their own class
  49. More reading » http://www.objc.io/issue-1/ » http://bendyworks.com/geekville/ articles/2014/2/single-responsibility- principle-ios » http://blog.securemacprogramming.com/?

    p=1222
  50. None
  51. Thanks » @chriseidhof » objc.io » uikonf.com » decksetapp.com

  52. Credits » The life of a software engineer - Manu

    Cornet