0

I'm going through Apple's Start Developing iOS Apps (Swift) tutorial and I'm confused on how they are using MVC.

They have a custom control (the view, a subclass of UIStackView), it is basically 5 stars that you can touch to rate a meal. Touching the third star would rate it a 3-star meal, etc. Their code that handles when one of the stars is tapped is in the same class that draws the stars to the screen. Shouldn't handling taps be done by a view controller? There is a view controller for this project, but it doesn't handle when stars are tapped.

Similarly, the "rating" (how many stars are selected) for this control is also stored with the view code. Shouldn't the rating be in a Model for this custom control?

Am I misunderstanding how this is all supposed to work? Or is it ok to have model, view, and controller in the same class together?

  • Are the stars saved to persistent storage as soon as the screen is tapped, or does that happen later? For example, when switching screens (views)? – user22815 Mar 2 '17 at 1:36
  • If you didn't know this was MVC, how would you approach it? – Robert Harvey Mar 2 '17 at 4:45
  • @RobertHarvey I have a web development background, which I think is why I'm confused. I would put some bare bones content as html, which I guess would be like a view. I'd have a JavaScript file listening for certain events, and that would ask some class on the server for some info (the model) and would then add html elements as needed back to the web page. – jabe Mar 2 '17 at 5:00
  • @Snowman The stars are a property, they change as soon as they are tapped. They exist inside a "Meal" object that is saved periodically, when "Meals" are added, changed, removed – jabe Mar 2 '17 at 6:21
  • 1
    Well, I think you should follow the conventions set forth by Apple. Model View Controller takes many forms, so it's difficult to categorically state that there's one correct way. – Robert Harvey Mar 2 '17 at 14:28
1

Shouldn't handling taps be done by a view controller?

No. The rating control is meant to be a self-contained unit. Think of a button or a slider: a button takes care of highlighting and unhighlighting itself in response to touches, and sends action messages to its target as the button changes state; a slider moves its thumb around as the touch moves, and sends action messages when its value changes. The rating control is the same.

If you put the code to handle basic user interaction in the view controller, then you'd need to put that same code in every view controller that used the ratings control. That doesn't promote reliability, maintainability, or ease of use. Since the ratings control should always behave the same way in response to the same touches, regardless of where it's used in an application, it makes sense to write that code once in the control.

Similarly, the "rating"...for this control is also stored with the view code. Shouldn't the rating be in a Model for this custom control?

Again, no. The control needs to remember the rating so that it knows how many stars to display each time it has to redraw itself. If the view had to fetch the rating from a model class for every redraw, that's a lot of unnecessary communication, and much worse, it creates a dependency between the view and the model.

In Apple's implementation of MVC, the view doesn't know anything about model classes, the model doesn't know anything about view classes, and controllers mediate between the two. When an app presents a "scene" or a collection of views, the view controller will get whatever information should be displayed, and configure the views that it manages. So the view controller in the sample app might find the rating value in the model and pass that rating to the rating control. There's no harm in the rating control remembering the value. If the user changes the rating, the control will send a message to its target, which will normally be the view controller, and the view controller can update the model. If some other interaction (like a tap on the "next record" button or whatever) causes the view controller to display some other information, it'll update its views as necessary with the appropriate model data.

You're right that the model is the place where the rating for a given record (or whatever is being displayed) should be stored, and the model is where the value comes from, but it's fine for the control to remember its value just as a slider remembers its value or a text view remembers its text.

Am I misunderstanding how this is all supposed to work?

I think you're just trying to understand it in terms of other MVC implementations, such as are often found in web frameworks. It's hard to put aside one's preconceptions and just look at how the model, view, and controller classes work in Apple's frameworks, but I can see that you're trying.

Or is it ok to have model, view, and controller in the same class together?

No, the whole point of the MVC paradigm is to help you figure out how to separate things into distinct roles. MVC (Apple's version, anyway) promotes flexibility and reusability by eliminating the dependencies between model and view classes. Your model classes shouldn't care how the data it contains will be presented to the user -- the interface could be Cocoa or Cocoa Touch, or a text only interface, or a web interface, and the model wouldn't have to change at all. Conversely, your views should know how to present the information they're given, but they shouldn't know or care where the information comes from or even what it really represents. For example, the "rating" property in your new control is really just a number that the user can set with a touch, and nothing in the control should depend on whether the number really represents a rating of something or some other quantity.

Update: I looked at the tutorial a few minutes ago, and you're right that RatingControl does act like both a view and a controller, but it does so in different contexts. To the view controller, RatingControl is just a view like any other. From the perspective of the buttons inside the control, though, RatingControl is a bit like a controller in that it creates and manages them, and it's also the target of the buttons' actions.

  • Keeping the rating control as a self contained unit makes sense, though in most other examples I've seen the controller handles button presses. Is it typical to handle actions in the controller and this rating control class in Apple's example is a rare case? Also, if we wanted to update the model when this happens, how would that be done? If the "rating control" view handles its own actions, how would the controller know to tell the model anything? – jabe Mar 3 '17 at 18:25
  • No, buttons handle touches themselves too! But when a button is tapped, it calls a method (it's action) in another object (it's target). Every control has a target and action, sometimes more than one. I haven't looked at that tutorial, but I'll bet the idea is that you'll follow the same pattern. – Caleb Mar 3 '17 at 19:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.