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

MVVM

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 MVVM

Avatar for Matt Diephouse

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