Discuss on MVC implementation on iPhone

后端 未结 4 991
刺人心
刺人心 2021-02-04 16:52

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 imple

4条回答
  •  北海茫月
    2021-02-04 17:33

    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.

提交回复
热议问题