How to deal with model classes in iOS application How to deal with model classes in iOS application ios ios

How to deal with model classes in iOS application


Abstract: I read carefully the topic Where to place the "Core Data Stack" in a Cocoa/Cocoa Touch application suggested by Brad Larson and I wrote a possible solution on how to deal with a model and different view controllers. The solution doesn't use Core Data, but I believe that the same design may be applied to Core Data apps.

Scenario: let's consider a simple application which stores information about products, such as name, description and price/unit. Once launched, the application shows a list of products (with a UITableView); when the user taps on a product name, the application presents product details in another view, updating the navigation bar with the product name.

Architecture The model is pretty simple here: an array of Product objects, each one with a name, a description and a price property.

The application has got three main views, mostly created by the Navigation template of Xcode: a UINavigationView (managed by the UINavigationController, instantiated in the app delegate), the default UITableView (managed by RootViewController and which is the first view shown by the UINavigationController) and a DetailView (managed by the DetailViewController class we have to write).

Let's see what's the big plan from the model point of view:

  1. The model is instantiated/loaded by the Application delegate as a NSMutableArray of Product objects;
  2. The pointer to the model is now passed to the first view controller of our hierarchy, UITableViewController, through a property. Actually, one could argue that the first controller in the hierarchy is the UINavigationController, so we should pass the reference to it and from it to the UITableViewController but... Apple says that UINavigationController shouldn't be subclassed, so we cannot add any property/method. And actually it makes sense, because the responsibility of an UINavigationController is always just the visualization management, not the model manipulation.
  3. When the user select a UITableCell, the UITableViewController creates a new DetailViewController (with the associated DetailView), passes the single selected product as a property and pushes the DetailView on the top of the UINavigation stack.

Here some code snippets:

Creation of the model:

// SimpleModelAppDelegate.m    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{    // products is a protected ivar    products = [[NSMutableArray alloc] init];    Product *p1 = [[Product alloc] initWithName:@"Gold" andDescription:@"Expensive metal" andUnitPrice:100];    Product *p2 = [[Product alloc] initWithName:@"Wood" andDescription:@"Inexpensive building material" andUnitPrice:10];    [products addObject:p1];    [products addObject:p2];    [p1 release];    [p2 release];    // Passing the model reference to the first shown controller     RootViewController *a = (RootViewController*)[self.navigationController.viewControllers objectAtIndex:0];    a.products = products;    // Add the navigation controller's view to the window and display    self.window.rootViewController = self.navigationController;    [self.window makeKeyAndVisible];    return YES;}- (void)dealloc{    // The app delegate is the owner of the model so it has to release it.    [products release];    [_window release];    [_navigationController release];    [super dealloc];}

The RootViewController can receive the model reference, since it has a NSMutableArray property:

// RootViewController.h#import <UIKit/UIKit.h>@interface RootViewController : UITableViewController@property (nonatomic, retain) NSMutableArray *products;@end

When the user taps on a product name, the RootViewController instantiates a new DetailViewController and passes the reference to the single product to it using a property again.

// RootViewController.m- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{    DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];    // Passing the model reference...    detailViewController.product = [products objectAtIndex:indexPath.row];    [self.navigationController pushViewController:detailViewController animated:YES];    [detailViewController release];}

And, at the end, the DetailViewController shows the model information setting its outlets in the viewDidLoad method.

// DetailViewController.m- (void)viewDidLoad{    [super viewDidLoad];    self.navigationItem.title = product.name;    self.descriptionLabel.text = product.description;    self.priceLabel.text = [NSString stringWithFormat:@"%.2f eur", product.unitPrice];}

You can download the full project here: http://dl.dropbox.com/u/1232650/linked/stackoverflow/SimpleModel.zip

I will really appreciate any comment to my solution, I am eager to learn ;)


More experienced colleagues recommend to have relevant property in AppDelegate. IMO it is better to use specific set of models in specific controller.


I'm a noob too but here's what I did. It's most like #2.

In applicationDidFinishLaunching, the app delegate creates an instance of the model.

My view controllers declare a property pointing to the model, but the type is a protocol (in my case id <GameModel>. Many of the properties in the protocol are declared as readonly.

In applicationDidFinishLaunching, the app delegate sets the property to point to the model it created.

What I don't like about:

One. Your view controllers shouldn't have to know about the structure of your app delegate. You might reuse the same view controller in another app, with a different app delegate type. You could make simple changes to your view controller code to fix that, or there are other ways to get around it, but why make it hard?

Three. I am not as fond of singletons as most people. The problem is they're single. What if you want to have multiple models loaded?

Four. ?!?!