nebs
nebs

Reputation: 4989

Should views hold model references?

Let's say we have the following classes:

View

@interface ArticleView : UIView
@property IBOutlet UILabel *titleLabel;
@property IBOutlet UILabel *bodyLabel;
@end

Model

@interface Article : NSObject
@property NSString *title;
@property NSString *body;
@end

Controller

@interface ArticleViewController : UIViewController
@property Article *myArticle;
@property ArticleView *myArticleView;
- (void)displayArticle;
@end

@implementation
- (void)displayArticle {
    // OPTION 1
    myArticleView.titleLabel.text = myArticle.title;
    myArticleView.bodyLabel.text = myArticle.body;    

    // ... or ...

    // OPTION 2
    myArticleView.article = myArticle;
}
@end

OPTION 1

OPTION 2

In OPTION 2, ArticleView will have to be changed to hold a reference to the model:

@interface ArticleView : UIView
@property IBOutlet UILabel *titleLabel;
@property IBOutlet UILabel *bodyLabel;
@property Article *article;
@end

The article setter can then be overwritten to update the view accordingly, like so:

- (void)setArticle:(Article *)newArticle {
    _article = newArticle;
    self.titleLabel.text = _article.title;
    self.bodyLabel.text = _article.body;
}

So my question is, which one of these two options is best in terms of OO and iOS/MVC best practices?

I've certainly seen both being used. I've seen OPTION 2 used commonly in UITableViewCell subclasses.

I've also read that views and models should be designed to be reusable and not depend on anything whereas view controllers are meant to be the least reusable of the bunch.

My gut feeling is to use OPTION 1 simply because I'd rather the view controller do the dirty work of binding the model to the view and let the model and view stay independent and unaware of each other. But since some views are designed to do one thing only then perhaps it's not so bad to have them tied to a specific model directly.

I'd love to hear your opinions on this.

Upvotes: 25

Views: 2865

Answers (6)

Rob
Rob

Reputation: 437632

In terms of Apple's official guidance on this topic, the MVC as a Compound Design Pattern section of the Concepts in Objective-C Programming document discusses both approaches, but clearly articulates Apple's preference of your option 1 over your option 2. In fact the Cocoa Core Competencies only lists option 1.

I've never regretted implementing the option 1 approach, but when I've cut corners and tried to have models and views interact directly, I've often regretted it when I've had to go back and modify a system at later date.

Upvotes: 0

PeteH
PeteH

Reputation: 2454

As others have said, Option 1 is the purer approach. The controller should be a "junction box" between the view and the model.

However a number of implementations of this type of approach (for example the framework that Microsoft call MVC) plump for Option 2. Certainly in Microsoft's case, the fact that the View and Model know about each other allows the IDE to create lots of boilerplate code, and save you the "trouble". The advantage of this is that you spend your time writing "function" code rather than "wiring" code. So, pure or not, you can appreciate where they're coming from.

As so often in software development, the choice between Option 1 and Option 2 boils down to purity versus pragmatism.

Upvotes: 0

justin
justin

Reputation: 104698

Yes, you have demonstrated understanding of the subject.

OPTION 1 is the classical structure of MVC, and I recommend it as your default route of the two presented.

Just because OPTION 1 is a purer definition, it doesn't mean that it need be applied everywhere possible.

The most frequent deviation I make is when an implementation is so specific and not reused that introducing a dedicated controller type just results in more code to write and maintain when the implementations are tiny, very specialized, not reusable, and will not grow substantially. If the program lends itself well to folding the V and the C into a single implementation and fits in something small (e.g. tens of lines of code), I don't worry about using OPTION 2.

Reality is more complicated than that, but the gist is: don't feel like you need to adhere to #1, although you probably won't understand how using #2 can introduce maintenance issues until you have written and maintained some moderate sized programs for a few years. Moving from one to the other can introduce many changes in a shipped program -- which could have been avoided.

Use of OPTION 2 should be the minority. If in doubt, use OPTION 1.

Either way, I believe the model should not know about the view or the controller.

To me, strict adherence is more important when writing reusable components.

Upvotes: 3

Hermann Klecker
Hermann Klecker

Reputation: 14068

Frankly, sometimes I do Option 2 myself. But Option 1 is 'out of the book'.

Upvotes: 1

Caleb
Caleb

Reputation: 125007

It's not always an either/or decision. Your first option is more typical of Apple's version of MVC; it's generally true in iOS that the model and view don't talk to each other directly, and the controller does most of the coordinating between them. However, it's not unreasonable to have a custom view that knows about specific classes within the larger model. You might well have an ArticleView that knows what to do with an Article, but the ArticleView should still receive any Article that it displays from the controller instead of getting it directly from the larger model.

One of the goals of MVC is to make model and view classes more reusable. If you keep your ArticleView very simple, so that the controller has to do all of the work of interpreting an Article, then you may actually be losing reusability -- every time you want to reuse ArticleView with a new view controller, you have to reproduce all the code that interprets the article for the ArticleView. Alternately, you always use the same view controller class to manage an ArticleView. Neither of these is really "reusable."

At the same time, you have to acknowledge that there's some natural coupling between Article and ArticleView simply by virtue of the fact that ArticleView is designed to display all the relevant details of an Article, whether it gets them directly from the Article or has them set by the view controller. If Article changes, there's a strong probability that ArticleView will have to change whether it knows about Article or not.

So, even though Article may be a model class, it can be okay to have a view that knows about it. What you don't want is an ArticleView that knows about the larger model and tries to fetch articles from the model itself. That limits the articles that you can display in ArticleView to just those that can be found where ArticleView looks -- it prevents you from displaying articles from other sources.

Upvotes: 31

Wain
Wain

Reputation: 119031

Option 1 is MVC. Option 2 is not.

OO is at a different level really, you have objects for the Model, View and Controller so you can't do much more to be OO.

Both options will of course work, but MVC exists for a reason (I'm sure you've already done some general reading like this) and you'll find that your code is easier to read, understand and reuse if you follow the principles of MVC.

Upvotes: -1

Related Questions