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.
Apart from using the name ViewModel (which itself is confusing if the class is full of logic), the one iron-clad rule of MVVM architecture is that you may never reference a View, from ViewModel.
Can I call the model from the View? Yes, you can. As long as you maintain the separation of concerns between M,V and C, you are free to call upon the Model (or the Controller) from the View. Most MVC diagrams show a bidirectional connection at least between View and Model.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With