问题
Im a using the MVC pattern for a while on different frameworks such as (swing, android, gwt ...) Now, I'm learning the iPhone framework and I am quite surprised about MVC implementation. The questions I am asking are about the view and controller interaction.
First of all, that's the way I conceive the MVC pattern :
The view and the controller communicate each other through an interface (one for the view and an other one for the controller)
In my conception of the MVC pattern, the controller do not have to know the attribute of the view. (for instance, the controller can't have a label attribute instance of the view but can ask the view to change the value of this label via a method of the view interface)
The advantage of not letting the controller directly work on view UI elements is a low coupling and therefore it is possible to test the view easier. The view can be launched and tested on isolation ( or with a mock controller ).
The point is, on iPhone the controllers (ViewController for instance) know directly the UI elements hence my incomprehension. My goal is not to criticise a framework I'm just learning. But if this is really working as I described it, I don't find that really clean...
Is there anybody more experimented with this framework who can give me details / explication ? Or if you feel disagree with my MVC approach, tell me ;)
What's more, I am asking if my approach is not neareast to MVP (described here : http://code.google.com/intl/fr/webtoolkit/articles/testing_methodologies_using_gwt.html) than MVC.
回答1:
MVC has meant different things since it was first formalized in Smalltalk, and the NeXTSTEP (Cocoa) version of MVC doesn't exactly match up with Smalltalk's. Smalltalk's break-down is basically like this:
- The Model holds data
- The View presents data
- The Controller manages user interaction
NeXTSTEP's break-down is in practice more like this:
- The Model holds the data
- The View draws the data
- The Controller manages the "logic" (including the "presentation" portion of drawing data)
I'm differentiating here between drawing and presenting in that NSView tends to be dumb about the "meaning" of the data. It just focuses on drawing pixels. So you tend to pass it actual strings rather than an object that the view tears apart and "presents."
It's not a huge difference, but it is the cause of things like what you're running into. The main shift IMO, is that with Cocoa/NeXTSTEP, the view classes have become more and more reusable. In becoming so reusable, more of the application-sensitive portions have needed to move out into the controller. This I believe is generally a benefit because it leads to fewer subclassses, more understandable code and more reusable code... most of the time. In particular, it allows you to more easily swap in views that do fancier drawing (a view that animates a particular way or alternates colors on rows or the like) without bumping into any application-specific logic which generally lives in the controllers.
That said, when a view is particularly complex, I do find it beneficial to create more specialized views that take a data object and manage their own presentation, more in the way I believe you are envisioning.
EDIT: One additional thing to note. Apple's example code often is terrible in terms of design. They almost never include model classes at all, and cram almost everything imaginable into the ViewControllers and worse: the AppController (which should be a very simple object in my opinion). This is generally because their sample code is trying to demonstrate some specific point and they don't want to include the complexity of breaking things up (or the author is being lazy; take your pick). So while I do believe that smart view controllers often work out well, you shouldn't take the example code as a demonstration of this. Unfortunately, there aren't a lot of canonical examples out there of good application-level Cocoa design, since most Cocoa apps are closed source. One good example to learn from is Adium. It is an excellent example of a large, well-designed, multi-developer Cocoa app.
回答2:
The iPhone ViewController is intended to manage a collection of views, all of which combine into a coherent interface. For example, a view controller may manage a scroll view with a dozen label views, a switch view, and two button views. Each UIView-derived piece handles the on-screen drawing of a specific element -- a button, a scroll layer, a label -- with the View Controller directing what data gets put where. So, a UIViewController-derived class focuses on the presentation (more View in the MVC sense), by marshaling data into the right UIView objects (like a Controller.) I think ViewController is an apt term for it.
Sometimes to managed a single screen, a UIViewController will have several other UIViewControllers for specific parts of the display. The UINavigationController, for example, maintains a stack of UIViewControllers each of which handle one page of the display. Cocoa is all about layering.
A UIViewController may and often does have a delegate (and sometimes a data source) that it uses to ask what data belongs in the views and to filter up user input. In my mind, that makes the delegates closer to the MVC Controllers because they are the classes that manage all the models and include any application (business) logic. The AppDelegate is the big one, in charge of managing the overall state of the application. The AppDelegate may keep track of all the data or it may dole out parts of the data to other delegates. I would expect the Facebook app to have one delegate for managing all the Events, another for Wall posts and a third for Photos, each of which report up to the AppDelegate for communicating with Facebook servers.
When I'm writing my apps, I tend to use CoreData for the MVC Model, Delegates for the MVC Controllers and leave the MVC Views to UIViewControllers tasked with wrangling the herds of UIViews.
回答3:
It's not a controller, it's a view controller. This is either explicit in the class name (UIViewController, UITableViewController) or implicit (UITabBarController, since a UITabBar is a view; UINavigationController, since navigation is a paradigm; and the UINavigationController has a very thin view).
The only non-view "Controller" that I can think of is a NSFetchedResultsContoller.
But why the odd design?
Part of it has to do with the iPhone UI paradigm: Users interact with a screenful at a time. If a "screenful" is not visible, then most of its memory can be reclaimed. UIViewControllers represent a screenful and manage how screenfuls interact with other screenfuls.
(Sure, Apple extended this slightly on the iPad to implement popovers/split views, but the two are still effectively "screenfuls" instead of generic views. View controllers are vaguely analogous to windows on a desktop OS, except that most of them aren't visible most of the time.)
Part of it has to do with CoreAnimation: A UIView handles drawing/layout and are backed by CALayers. CALayers effectively represent textured polys on the GPU; the "layer content" (i.e. texture) cannot be arbitrarily unloaded to free memory. (I'm not entirely sure why, but it means you can set the content to a CGImage once and leave it alone.) Since a lot of the view's properties are backed by layer properties (frame, bounds, center, contentStretch, ...), it's a bit silly to let a view exist without a layer. The end result is that views are heavyweight and they occasionally need to disappear when memory is scarce, so the view controller needs to keep track of things that should persist across view unload/reload (scroll position, currently selected item, ...). Yes, it could ask the view to serialize itself, but serialization is icky and most things don't need to be serialized.
Part of it has to do with laziness: You'll need to implement the view controller to handle how it interacts with other view controllers. On the other hand, views do autoresizing — if you're happy to set the layout in the nib or in -viewDidLoad, you often don't need to write a custom view. Laziness dictates that you don't, so layout often happens in the view controller.
Personally, I implement a "smart" view when it seems to make more sense. Take, for example, the Weather app: When the view loads, you have to display the weather for a bunch of days in each cell (which may or may not be a table view cell; it doesn't matter). When you get an update, you have to update all the cells. You could implement -[WeatherViewController updateCell:], but it seems to make much more sense to just have -[WeatherCell setWeather:] and pass it your model. There's a lot less clutter in the view controller.
I also blame laziness and maintainability: Sometimes it's just easier to have everything in one file, and sometimes having semi-duplicate code with minor specializations is easier than writing a generic view that supports all its use cases. It's a lot nicer than Enterprise Java, where it's common to have a function-that-calls-a-function-that-calls-a-function-that-calls-a-(function-of-a-singleton-that's-instantiated-with-a-factory-with-some-class-that-you-need-to-track-down)-that-calls-a-function-that-calls-a-function to find out that the Enterprise Software is using a password hashing algorithm that can be expressed in 1 line of Python. (I only exaggerate slightly.)
(So what happens when you decide that the general layout of the weather cell is suitable for displaying, say, moon phase/visibility? Move the generic stuff to a superclass and make an AstronomerCell, or whatever.)
Also, if your views can't work with a mock controller, you're doing it wrong. Views should not know about their view controller; the view controller should register itself as an action-target (addAction:target:forControlEvents:, I think) or an appropriate delegate. Neither of those expect the target to be a view controller.
回答4:
This is just a guess. But my guess is that one reason the the View and the Controller end up more tightly coupled in Mac/iPhone implementations is that if you decouple the interaction control and the presentation too much, the likelyhood that you end up with an uglier and less intuitive feeling interface increases. Whereas more tight coupling encourages the developer into making the the control of the model more closely fit subtile differences in user behavior given their perceptual response to the view presentation. You end up with more UI optimal but less portable code. Value judgements required.
来源:https://stackoverflow.com/questions/3845951/discuss-on-mvc-implementation-on-iphone