Testing the UIViewController as Cocoa

EDIT: Does anyone have useful links on this topic? I mean good methods for writing reusable code and "abstraction"?

tl; dr - Read this comment Testing a UIViewController like Cocoa ones

I have 3 UITableViewController :

  • CategoriesViewController
  • RecipesViewController
  • IngredientsViewController

They are ordered hierarchically. The following is an example hierarchy:

  • Dessert (category)
    • Brownie (recipe)
      • Milk (ingredient)
      • Chocolate (ingredient)
      • Oil (ingredient)

enter image description here

Each of them has similar functionality with the others. For example, everyone has sorting (moving lines), deleting, adding (representing a modal representation), etc.

Currently, I have repeated all the code for each view controller, customizing the parts associated with each. For example, they all have an instance variable like this:

CategoriesViewController.m :

 @implementation CategoriesViewController { NSMutableArray *categories; } 

RecipesViewController.m :

 @implementation RecipesViewController { NSMutableArray *recipes; } 

IngredientsViewController.m :

 @implementation IngredientsViewController { NSMutableArray *ingredients; } 

Since I think there is a better way to organize this view controller, I tried to create the skeleton MyListViewController.h :

 @interface MyListViewController : UITableViewController @property (nonatomic, strong) NSMutableArray *list; @end 

MyListViewController.m :

 @implementation MyListViewController - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [_list count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"ListCell"]; id currentObject = [_list objectAtIndex:indexPath.row]; cell.textLabel.text = [currentObject valueForKey:@"name"]; return cell; } - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // get item to delete id object = [_list objectAtIndex:indexPath.row]; // remove it from list [_list removeObjectAtIndex:indexPath.row]; // call callback [self didFinishDeletingItem:object]; // delete row from tableview [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; } } - (void)didFinishDeletingItem:(id)item { } 

Thus, once I have subclassed it, I need to assign list ivar to my data structure. And I can even override methods like didFinishDeletingItem: to customize the behavior of each controller.

Since this is the first time I will use the best practices for writing and organizing code in this way, I would like to know your opinions and which are the best ways for abstract classes to reuse them correctly with the DRY principle.

+4
source share
2 answers

(This should be a comment, but I can not comment). Do not [_list count]; Use the property: [self.list count] Only access ivar in accessories, or you will bite somewhere along the line. This also applies to other places where you use _list instead of self.list.

Your skeleton class looks fine and this is good coding. Expanding on this: if there is only one other in the real data for the elements, you can create different subclasses of UITableViewCell. MyListViewController can see what types of objects are contained in NSArray (or you can set a flag in MyListViewCOntroller) and use the corresponding UITableViewCell on this basis (and therefore display the data correctly.)

+1
source

From what I understand, you can do this in one of the following ways:

  • Since you said that your screens and behavior are the same, you can use the same MyListViewController class and when creating an instance you can assign / populate the list array. This is a traditional approach.
  • Alternatively, if your classes (Categories, Recipes, Ingredients) are slightly different in behavior, you can subclass them in MyListViewContrller. You can do this in the .h file as follows:

    @interface CategoriesViewController: MyListViewController {

In Xcode, you can select a superclass when creating a new class file.

Hope this helps in some way

+3
source

Source: https://habr.com/ru/post/1501129/


All Articles