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)
Related
I am working on a bowling scoring app and am having a tough time figuring out what UI classes and controls to use for the paradigm I want. Here's the ideal:
I want to draw on an ipad (in landscape) a bowling scoresheet exactly like the oldstyle paper you see in a bowling alley with the 11 boxes for each scorer. I want to be able to input scores by touch the boxes etc, be able to print an old school bowling scoresheet (with the lines etc) at the end, and have the app essentially be what I call "hot paper". I want a full scoring sheet for 5 bowlers for example inside appropriate scroll controls so an olde phart using it can pinch or swipe to move around the paper to input scores.
This is targeted at olde pharts exclusively and they want it to act like paper. While I have written simple apps with TableViews and the like, I am not sure whether to use a Collection, Grid, or what, and what is the right way to draw so that I can send the completed "paper" scoresheet to a printer.
I am looking for some iOS genius who can recommend simply what classes I should be using for the elements - for example each row of the score sheet etc. Also shwhat elements should I use storyboards for and what should I do programmatically? I am quite storyboard challenged and usually do everything programmatically - I amgreat with making things work but awful on making them pretty.
I assume you want something like this:
Personally, I would draw/construct it entirely in code, as it so straightforwardly geometrical and repetitive. Just think of it as a hierarchy of views, each of which is itself a class that knows how to draw/construct itself. For example, MyFrameView is the box for one frame, which might or might not be the tenth frame. Then MyPlayerRowView simply gives itself ten MyFrameViews horizontally, and MySheetView gives itself five MyPlayerRowViews vertically. And presto, just three self-drawing classes so far and yet we've constructed almost the entire grid.
The only question is the underlying interactive interface. How should information be entered? What is the user to be allowed to do? That is a problem for you to solve. For example, should a MyFrameView just contain a UITextField? Or do you want the user to tap it and have some sort of "enter score" interface pop up? Those are the sorts of things you'll have to think about; in the latter case, you'll use a gesture recognizer to detect the tap and respond accordingly.
This values get from web servies. Totally i want to show 4 layer to display[i show here only 2 layer]. some times in web servies values are come more means the layer become big and show the values.same and anther 3 layers are displayed. help me..!
Use UIScrollView or Freeform make it independent means don't use static value make it dynamic whatever number of layers you are getting from server and according to that adjust content size of UIScrollView.
First of all. This view (and design) doesn't really follow any iOS consistency. The Apple human interface guidelines are there to help you with finding the correct way to do something.
Right...
Do you need to show all the options at the same time? i.e. do you need all four "layers" on the screen at the same time? If so, why? What is the user supposed to do with this screen?
Is the user selecting one option from each layer? Multiple options from each layer? etc...
With either of these I would go down the route of using a navigation controller with a single UITableViewController to display each layer.
So, the user gets a nice list of options...
dumbell
E-Zbar
cable
barbel
...
And selects one (or many) of them.
Then the second "layer" is pushed onto the navigation stack and the user gets another nice list...
incline
decline
close-grip
rotating
...
This way the user has to only concentrate on one task and each list is deployed nicely and readably for them.
If I was a user and was presented with a big list of buttons like your design I wouldn't know what I was supposed to do.
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.
Using UICollectionView and excellent help given on here on StackOverflow, I've been able to build a "Gantt Chart" style control for my iPhone:
Cosmetics aside (I'm doing the functional right now, I've got a graphics designer on tap to look at colors and all that).
Background aside, the spans were relatively straightforward to do with a custom UICollectionViewLayout subclass. Each span is an item.
But I need to add some functionality, and am unsure how to proceed. Where I'm trying to go is illustrated roughly as:
Sketchy cosmetics aside, the point is that I want to "annotate" whatever the currently selected span is with additional information (I promise to find someone to help me look it pretty). And I want them to be active, I'm not sure if it brings up an editing control or does drag, but I want to be able recognize gestures on either the numbers or the bold lines and do things with them, distinct from touching on the span which drives selection.
I can think of (at least) 3 ways to try and implement this:
Use supplementary views. Cause selection to invalidateLayout, detect the selected state in my prepareLayout, and generate additional layout attributes for the two anchors. Implement a subclass of UICollectionReusableView which does the drawing, and adds touchable subviews (or its own gesture recognizers). This feels... wrong. I get the idea that supplementary views are more for headers and footers, not for controls that come and go as the selection state changes. But maybe it's an appropriate extension of the facility?
Use the backgroundView (or selectedBackgroundView, not sure it matters) of my current SpanCell class (which is a subclass of UICollectionViewCell). As long as I disable clipsToBounds, I can draw the annotation around the bounds of the span. I'll have to give it some knowledge of the big picture to find the endpoints, but that's not too offensive. I would just show/hide this view in response to selection changes. This seems like the best way to do it.
Do it in the main backgroundView of the entire UICollectionView. As shown, I've already got a specialized backgroundView which shows the the current time grid, strip style. I could further extend this view to draw annotations and manage touchable sub controls in response to selection changes. This would give me most direct implementation, but it feels like I'll end up with a big monster "doing too many jobs" object for the background.
Question then, for those who have more experience, is which route would you go? Would it be one of the above 3? Or something different? And why?
While your question is very technical with UICollectionView implementation, which I am not very familiar with, this seems like a job for the container (in this case, the collection view). Imagine you need your annotation to consider, in addition to the selected item, other items? Like for example, avoiding collision between annotation lines and another item?
For me, option number 3 seems like the most correct one. If you fear a large class, you can extern it to an annotation controller class, which should be notified whenever the annotations should be updated.
I'm building an app that has views that are build programmatically. That is, I am fetching data from a database that contains information on things like the number, size and placement of buttons in a view. At some point, there will be code that uses this data to instantiate new subviews and set them up. My question is, where should this code go? The view, the viewController, or somewhere else. It seems to me that this is a grey area regarding typical MVC principles. Should a view accept data, and then know how to draw itself using this data? Or perhaps, a viewController is responsible for building all the various subviews, and then simply adding them to the view.
Thoughts? Thanks.
I agree that it's a gray area. Personally, I make a decision like that based on whether it's the data that needs manipulated or the display of that data. For example, a view controller displaying a date may need to process various dates (ie, a data represented as a DMY struct vs. a date represented as a seconds count from some reference time) into a format suitable for the view, while the view itself may be only capable of receiving one particular format (ie, DMY) and is responsible for displaying that. That's the sort of line I tend to draw between the two -- displaying data (the view) vs. interpreting data (the controller).
In your example of reconfiguring a view I would probably put most of the logic into the controller since it involves interpreting the data. I would design the view to accept configuration details such as how many items to display and what sort of layout format to use (think of a UITableViewCell), but I would design the controller to interpret the data to decide how many items and what to put in the various fields within the view (like a UITableViewController).