iOS: On not duplicating the view hierarchy in the MVC model - ios

This question is related to MVC (in iOS programming), and to a book wherein the author uses MVC somewhat differently from what I have seen before.
I think I have a pretty clear understanding of Apple's interpretation of the MVC-pattern, as it is explained in Stanford's on-line course on iOS programming. That is to say, the Model and the View should be independent, and the Controller should act as the glue in between.
I have implemented a few iOS applications where the view contains movable objects. In doing so, the movable objects have been implemented as Sub-views (or CALayer:s), and they have been instantiated by the main view. A sub-view knows its own location and size (in the frame property), but that information is often duplicated in my model object. In fact, the entire view hierarchy is often represented in the model (and I blame much of my spagetti coding to this redundancy).
In the book Beginning iOS Game Development the author, Patrick Alessi, implements a game called blocked (a.k.a breakout). In his implementation, the model allocates and initializes an array of UIView objects (the blocks in the breakout game) and the controller then adds them to the view. When a block later on should disappear, the model removes it from the superview as well as from the array.
I have mixed feelings of Alessi's implementation. It avoids the duplication of data! But how does it relate to MVC? I ask this question to broaden my own understanding of MVC. Is it possible to regard an UIView object as both a view and as a model object?

Well it's a game not an information processing application. The model is really closely tied to the view because you care about where on screen the blocks are so you can calculate if they are being hit and so on. Same goes for 3D shooters where most information concerns things that have a location somewhere in 3D space. Just make sure that you manage to refactor out most code that doesn't directly involve drawing the View out of the UIView subclass.
Things like scoring, player data and ads should use the traditional MVC model.

It's pretty common for an app to have a representation of each model object in the view hierarchy.
As you say, the glue belongs in the controller. If I were writing the breakout game, I would put the logic to create the array of view objects in the controller.
In a game app it might make sense to stretch or even abandon the MVC design pattern. The model object (a brick) could be a view object at the same time. The controller would manage an array of bricks directly, where that management would involve updating the coordinates of the bricks, their onscreen/offscreen status, etc. That's probably how I would tackle a game like that.

SmallTalk was initially considered model-view, with the controller role evolving naturally before Objective-C's welding of that language to C. I think there's correspondingly an extent to which you can view the controller as being a little less concrete in purpose; certainly it's to provide some abstraction between the two components but therefore the general of avoiding redundant abstractions has to apply.
Extreme example: your model object is an NSString. You want to be able to put strings on screen. You've got the code to render an individual character; that's obviously a view thing. The NSString can vend a list of its characters; that's obviously a model thing. Do you really need a formal, separate controller class to spoon feed the characters one by one to a view or views? Is it helpful to have one?
I think most people therefore allow scenarios where a view can render, in its entirety, a model object, even if it's a much more complicated compound than a string. Suppose you had an address book object which compounded a name and a phone number. Most people would allow a view to receive that object and compose subviews for display internally. Often that will mean the view talking directly to the model and possibly the model doing some work for the view — if the view needs the phone number then why should it care whether that property is implemented as #dynamic? If the model evolves from a standard stored property to something that requires a more complicated lookup, why should that implicate changes to the view?
The controller then becomes responsible primarily for composing the complete interface. It glues together the constituent parts to allow collections of renderable objects to form a coherent display.
Like you I would have severe misgivings about Alessi permitting a model directly to manipulate a view hierarchy. The model should absolutely not involve itself in view stuff. The onus should be on views to display model stuff, with the controller decoupling where a decoupling makes sense.

Related

Is it appropriate to have view controllers that have multiple views?

I have a quick question in regards to my app that I am developing for school. In my app we have 5 unique games that the user can play. However, each game has 2 modes, normal and hard. What is the best way about going to do this. Currently I have my first game as two separate view controllers and are called based on the difficulty that is wanted(one called normal_cstars and hard_cstars). I am wondering if this is efficient because each view controller has a .h, .m, and a .xib. Is it possible to have a view controller that has two separate views and how would you go about accomplishing this.
Thanks,
Ryan Wong
Of course. You can pick which one of the two views you display inside your viewcontrollers. Just send self.view in the view controller to be the view you'd like to use.
One way to architect this is to have two separate view classes that share the same controls. The controls are all handled by the view controller while the views each draw their own layout.
And don't be worried about sharing subviews among the two main views -- or you can keep your two view controllers, and just have shared classes that make up the views and controls of each view controller's presentation. Just because you have two view controllers doesn't mean you have to have redundancy code. Split things out into separate classes, from your animated views to your controls.
There are a lot of other possibilities. Look at some of Apple's samples to see how multiple view controllers are used.
Do you really think that you need two separate views? (I am not sure about your game though)
Since game modes are Model specific, a model with behaviour "Normal" or "Hard" will actually render the game in a view.
If near future, if you want to implement a mode "Easy" then you end up with another view controller and might encounter code redundancy.
Solution I would think:
Create a inheritance over composition pattern for your model objects.
A view controller will be much more generic and tells view to render based on the mode
Now the base class of the model will implement generic methods and since the model has mode as composition, the view will render the game objects based on it.
Advantages? - well we have not violated the Open-Closed Principle.
And again there are various design patterns out there to achieve this. Its up to you to decide which suits the best for the requirements.

How can I clone a UITableView from one controller to another so it stays in synch?

I found this in SO; it doesn't exactly answer my question, which is: is there a way to clone a UITableView from one controller to another while using Storyboards and maintain synchronization?
You can clone them in the sense that their initial property values remain the same, like position, layout etc. For this, just copy the UITableView from storyboard, go to destination view controller and paste it there.
If you share same UITableView object between two view controllers, it is still possible, but you must estimate how much work you would have to do yourself. When a view controller solely handles a table view, much of the work is done under the hood and table is handed over to you. In case of your UITableView shared between two view controllers, you would have to play with it quite carefully. You need to take care of entire life cycle of the view - see the usual methods like viewDidLoad, viewDidAppear and so on. How would you take care of them when your view exists in two scenes? Maybe you would be inventing a unique design pattern - if at all you find the most optimistic and programmatically correct way to accomplish it.
With storyboards, you cannot achieve cloning up to the level wherein data changes will reflect seamlessly between the two. Storyboard is, as the name suggest, just a board, where you can draw things to know how would they look initially, before your code takes over.
In order to achieve what you want, you have to create a shared model that updates two table views through proper delegate methods. Most likely such a model (NSArray, or any such collections as per your requirement) can reside inside a shared class (app delegate isn't a wrong choice), from where both your view controllers can refer to it. That is neat practice, it not only is right from programming perspective but also extensible and helpful to anyone who deals with the code any time.
For details about how to update UI from your model, there is nothing better than starting from scratch, going through the books I mean.
I am not aware of such possibilities.
I would pass the tableview source object amongst different controllers and let the view controller handle their own table view.
I think the best approach would be to use a framework such as the freely available Sensible TableView, then use the same model for both table views. This should be really straight forward.

The correct way to communicate between several different view controllers in Objective C

I have an app that was extremely simple until today. It had a tab bar view controller with 3 tabs. The middle tab was a camera, and the other 2 were table views. The tab bar view controller was the central hub for all the data in the app. So from there, I would set a table's data array as:
(PLEListViewController*)[self.viewControllers objectAtIndex:0] setList:newList];
Obviously, PLEListViewController is my UITableView subclass.
So now, I want to wrap the table views in a UINavigationController, which is fairly simple. But now, that line of code turns into:
[(PLEListViewController*)((UINavigationController*)[self.viewControllers objectAtIndex:0]).topViewController setList:newList];
There are 15 lines in the code that do this, which is not pleasant.
So my question: what is a more elegant way of doing this that I'm missing?
It's good that you're asking this and seeing the issue now. Your problem is can be found in your question. The answer to "the correct way to communicate between several different view controllers in Objective C" is "don't." Specifically, your mistake is here:
The tab bar view controller was the central hub for all the data in the app.
A view controller should never hold any of the data in the app. Your data should live in your model classes. All the view controllers should talk to the model classes. They should very seldom talk to each other. That's the heart of MVC.
So, you move your "list" (whatever that is, doesn't matter) into some model object that all the view controllers know about. That model object can be a singleton, or often better, it can be passed to the view controllers when they are created. When things change, you change the model. And in viewWillAppear: you update your view controller to match the current state of the model.
Never assume that a view controller exists when it is not currently on screen. If your design requires that a non-active view controller exist, then your design needs fixing.
You need to work with your architecture. Make the appropriate datasource and delegation protocols to ensure your classes can communicate anonymously. What you currently have is very inflexible and it will get worse as your app grows/changes.
You want to make things more loosely-coupled, instead of coding explicit traversal of links between your objects in your code.
Assuming you have one data model that is displayed in various places in your application, I think there are 2 approaches that could help...
One is to use your view controller hierarchy.. For example, use [ self enclosingTabBarController ] to find your closest parent tab bar controller and get it's data model property. Substitute -enclosingTabBarController with what works better for your application.
The other approach would be a "data model as a singleton" approach. For this you can either
move the data to your application delegate and access it via ((MyApplicationDelegateClass*)[ UIApplication sharedApplication ].delegate).dataModel
or
have a singleton data model object for your app, and access it via [ MyDataModelClass sharedModel ]
In any case you are moving to a looser coupling, which requires less explicit traversal of links between objects in your app. Less is more!

Pattern for class to manage view controller flow

At the moment I'm using a Singleton class to do some work but I'm wondering if there is something better.
I have an app that has a completely dynamic work flow. It uses a navigation controller but the order of the view controllers depends entirely on some data that is downloaded from our server.
The entire workflow is downloaded and saved in an array.
The "main menu" screen of the app has several choices (settings, recent, etc...) these are fixed but one of them is the dynamic one. It always starts with the same type of view controller but from then on it depends on what you choose.
Description
There are 4 different types of these dynamic controllers.
Table View Controller with single selection and detail indicators.
Table View Controller with multiple selection and checkmarks.
View Controller with a text field and keyboard.
View Controller (with other related VCs) used for searching for accounts on the server.
When you press the option "New Event" on the main menu the menu then goes off to the singleton (EventManager) and tells it to start a new event.
The singleton then pushes a single selection dynamic view on the nav controller and gives it the initial options.
From here on the singleton picks up all the selections and works out what type of view is required next.
I hope this is making sense
Anyway, I don't like the singleton pattern here as I don't think it should be a singleton.
What I would like is a class that I can create from a ViewController and this class will then control the pushing and popping and flow of data between a load of different view controllers. Then when you go back to the main menu this class can go away so I create a new class each time.
Is there a pattern that I can look at that will do this? Or should I stick with a singleton like I am now?
I hope this makes sense.
EDIT
Could I use a UIPageViewController for this? Then the datasource/delegate object of the UIPageViewController will take the place of the Singleton I am currently using... or something?
ADDING PHOTO FROM TWITTER REQUEST
Each VC along the flow has no idea what cam before it or what comes next. All they do is call back to the singleton to say "This value was selected" or "This text was entered" etc...
The singleton then stores that info and works out what comes next and pushes the next VC onto the stack.
It needs to be able to move back along the stack so the user can go back to change something etc...
It's all working as it is I just don't like the use of the singleton.
Lots of comments here in order of importance.
Everything you've described here sounds really good, even down to the naming. "EventManager" sort of sounds like it manages all "events" in the system (so I'd expect there to be a class called Event, but that's a tiny quibble and the name is likely still very good). There are other good designs, but I wouldn't have any problem with yours.
I agree that this does look like a good fit for UIPageViewController. You should certainly investigate that to see if it's the right fit. It's always nice to use a built-in controller if you can.
There's no reason to strongly avoid singletons. They are a natural part of iOS development and fairly common in good Cocoa design. They should be "shared" singletons generally (never create "strict" singletons that override +allocWithZone:). This just creates an easy-to-access instance rather than a true "singleton." This is the way things like NSNotificationCenter work and is often a very good pattern.
Singletons are best when many random pieces of the system need to access them directly and passing them around to everyone would be a lot of overhead (especially if many of the pieces you'd have to pass the object to don't need it themselves). Again, think NSNotificationCenter. If the users of it are mostly contiguous (i.e. most objects you would pass it to actually need it themselves), then just create one at the start of the program and pass it around. That sounds like your situation, so your intuition about it seems good. Just de-singleton it and pass it. Easy change.
But I'd definitely dig into UIPageViewController. It could match your problem very well.

Understanding Model-View-Controller

I have an app where I want to have one “background” view (view controller view), and on top of that, multiple UIViews that draw themselves as circles. I just don't understand how to implement all of this while still adhering to MVC...
The model and the view should be different. Does this mean that I generally need one set of header and implementation files for the view and another (separate) set for the model — even if my object is just a Circle class? Or, would I have one Circle.h and Circle.m set, and then inside the header file have two interface blocks, one for the model and one for the view, and two implementation blocks (again, one for the model and one for the view)?
I’ve seen a few people recommend using the view controller to handle all of the views in loadView, and to avoid creating separate custom view objects; does this mean that I shouldn’t create a separate set of .h and .m files for the view? The latter seems a lot more organized in terms of design to me.
Also, if I were to have multiple view objects and multiple model objects handled by the view controller, I would store these in two arrays in the controller — one for models, and another for views. Right? My question is: When I use key-value observing on each model, how would I, for each model object, alter the correct corresponding view object (assuming that indexes are not the same for both objects in both arrays)?
I was thinking about using a pointer to the model object inside of the view, and KVOing from the view to the model — but then it doesn’t go through the controller and thus breaks MVC altogether, right?
Thank you in advance.
MVC is a big, broad idea. It's more a guiding philosophy than a specific rule, and it's not always implemented the same way. Read Apple's discussion of MVC to appreciate the difference between traditional MVC and MVC in Cocoa.
It's hard to say how to apply MVC to your app because you haven't told us what the app should do, and also it doesn't sound like a realistic application. So I'll do my best here and make some assumptions along the way. An app that just draws a bunch of circles in fixed locations on a background isn't very interesting -- it could be almost all views, barely any need for a controller at all. So lets say that the circles are all moving in different directions, are drawn in different colors, and change in size over time. Now you start to have a need for a model, so that you can keep track of the data that these circles represent, and a controller to translate the model into terms that can be represented by the views.
Since you asked specifically about drawing circles, lets start with the view. It seems like a good idea to have a custom view that knows how to draw a circle given the necessary parameters: area, color, and position. You'd probably make these things properties, and override -drawRect: such that it draws a circle of the given area in the given color.
We don't know what these circles represent, but it's not much fun if they don't represent something, so let's postulate that the app's job is to help us compare corporations. We have data on revenue, market capitalization, number of employees, credit rating, name, ticker, etc. You could create a custom object to store all the data for each corporation, or you could put it all in a dictionary. Our model is a set of these custom objects or dictionaries.
Notice that the circle views don't know anything about corporations, and the model doesn't know anything about circles. This is A Good Thing. It's also where the controller comes in. The controller is where you put the code that expresses the model visually using the views. It also interprets events from the views, updating the model as necessary. So, our controller knows both about the particulars of the corporations, and the properties of the circle view. It creates a circle view for each corporation in the model. I want the area of a circle to correspond to the corporation's market cap, the vertical position to represent the revenue, and the horizontal position to indicate number of employees. We'll assign a color based on the corporation's credit rating. The controller should, of course, keep track of all the circle views and some way to map between circle views and corporations.
Now you've got something. It's still a pretty simple application, but you've got a useful chart comparing corporations in several dimensions. Let's improve it.
First, it's hard to know which circle represents which corporation. It would be nice if a circle view could optionally display some text. Let's add title and subtitle properties, and modify -drawRect: to draw these strings above and below the circle, respectively. We'll also change the controller so that a tap or click on a circle sets the title and subtitle of that circle to it's corporation's name and ticker symbol, or clears them if they were previously set.
Second, it's nice to compare corporations at a moment in time, but more interesting if we can show changes over time. Let's change the model to include historical data for revenue, market cap, employees, and rating. We can update the controller so that it can uses the historical data to animate the circles.
The first change related to how we draw information on the screen, and didn't require any modification to the model at all. The second change was about what data we have to work with, and didn't require any change to the view at all. You could easily re-use the circle view to represent some other kind of data, or maybe even to be the puck in an air hockey game. It's just a colored circle. And you could re-use the model in another app that deals with the same kind of data.
I'm sure the hypothetical application in this very long-winded explanation-by-example bears roughly zero resemblance to your own application, but perhaps it'll help to explain why MVC is useful and inform the structure of your own application. Good luck.
I got good explanation from CS193P IPHONE APPLICATION DEVELOPMENT (Winter 2013).
Model-View-controller:
Divide all objects into three camps:
Model : What your application is (A Card , A Deck , card game logic)
Controller : How your model is presented to user (UI Logic). Controller knows everything about the UI.
View : Your controller's minions.
How those camp communicate :
Don't cross yellow line.
You can cross over Dashed white line.
some special rules are there for crossing solid white line.
Controller --> View (via Outlet)
View --> Controller (via Data source (count, dataAt), delegate(will, should, did), Target-action)
Model --> Contoller (via Notification & Key Value Observing)

Resources