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

MVVM

 MVVM

Matt Diephouse

May 13, 2014
Tweet

More Decks by Matt Diephouse

Other Decks in Programming

Transcript

  1. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return self.fetchedResultsController.sections.count; } - (NSInteger)tableView:(UITableView *)tableView

    numberOfRowsInSection:(NSInteger)section { id<NSFetchedResultsSectionInfo> info = self.fetchedResultsController.sections[section]; return info.numberOfObjects; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:...]; RCPRecipe *recipe = [self.fetchedResultsController objectAtIndexPath:indexPath]; cell.textLabel.text = [NSString stringWithFormat:@"%@ by %@", recipe.name, recipe.author.name]; return cell; }
  2. MVC 1.0 ▸ Logic is tied to presentation ▸ It

    can only be tested visually ▸ The code is verbose ▸ Tightly coupled to the database and model ▸ No separation of concerns
  3. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return self.numberOfSections; } - (NSInteger)tableView:(UITableView *)tableView

    numberOfRowsInSection:(NSInteger)section { return [self numberOfRecipesInSection:section]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:...]; RCPRecipe *recipe = [self recipeAtIndexPath:indexPath]; cell.textLabel.text = [NSString stringWithFormat:@"%@ by %@", recipe.name, recipe.author.name]; return cell; }
  4. - (NSInteger)numberOfSections { return self.fetchedResultsController.sections.count; } - (NSInteger)numberOfRecipesInSection:(NSInteger)section { id<NSFetchedResultsSectionInfo>

    info = self.fetchedResultsController.sections[section]; return info.numberOfObjects; } - (RCPRecipe *)recipeAtIndexPath:(NSIndexPath *)indexPath { return [self.fetchedResultsController objectAtIndexPath:indexPath]; }
  5. MVC 2.0 ▸ Some logic could be tested in code

    ▸ Partial separation of concerns ▸ Reusable methods for getting model objects ▸ Slightly less verbose
  6. MVC 2.0 ▸ Some logic is still tied to presentation

    ▸ Still requires visual testing ▸ Tightly coupled to the model
  7. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return self.numberOfSections; } - (NSInteger)tableView:(UITableView *)tableView

    numberOfRowsInSection:(NSInteger)section { return [self numberOfRecipesInSection:section]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:...]; RCPRecipe *recipe = [self recipeAtIndexPath:indexPath]; cell.textLabel.text = [self displayNameForRecipe:recipe]; return cell; }
  8. MVC 3.0 ▸ Tightly coupled to the model ▸ Testing

    per-row logic requires an entire table view ▸ Logic could easily depend on view
  9. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return self.viewModel.numberOfSections; } - (NSInteger)tableView:(UITableView *)tableView

    numberOfRowsInSection:(NSInteger)section { return [self.viewModel numberOfRecipesInSection:section]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:...]; RCPRecipeViewModel *viewModel = [self.viewModel viewModelAtIndexPath:indexPath]; cell.textLabel.text = viewModel.displayName; return cell; }
  10. @interface RCPRecipeListViewModel : NSObject @property (assign, nonatomic) NSInteger numberOfSections; -

    (NSInteger)numberOfRecipesInSection:(NSInteger)section; - (RCPRecipeViewModel *)viewModelAtIndexPath:(NSIndexPath *)indexPath; @end
  11. MVVM ▸ Separation of concerns ▸ Testable in code ▸

    Easy to test per-row logic ▸ Loosely coupled ▸ Independent of UIKit/AppKit ▸ Easily have different row types