MVC架构中控制器的职责

时间:2013-08-14 17:04:38

标签: ios design-patterns model-view-controller

我有一个当前的代码库,我想重构。 控制器(或熟悉iOS的人的视图控制器)大约有2000行并且做了很多东西。

Controller is responsible for : 
1) Communicating between view and model

1.1) Handling callbacks / actions from view
1.2) Handling gestures.
1.3) Passing data from model to view. 

2) Making web request if model is empty. 

2.1) preparing URL and sending request to connection handler. 
2.2) Parsing logic

3) Customizing UI 

3.1) Minor UI modifications. 

4) Business logic. 

4.1) A little bit of code deals with business logic of calculation some reports. 

我在考虑将一些职责委托给模型和视图。 有关如何去做的任何想法?

另外,更具体地说,我想知道谁负责制作网页请求模型或控制器?

2 个答案:

答案 0 :(得分:2)

在编写易于维护的代码时,有几个概念对我有用:

  1. 除了具体的模型对象(例如,如果从服务请求天气信息,您可能有一个代表特定天气报告的Weather类,例如citytemperaturenarrative属性),我还将使用一个数据控制器对象来协调从缓存,持久存储或从Web请求对象(通常按顺序) )。您希望警惕完全依赖Web服务的简单请求,因为在设计响应式UI时,缓存等非常重要。

    对我而言,关键是我很少想要观察或查看控制器弄乱这个细节(但是,我承认,在琐碎的情况下,我直接从控制器完成了请求)。理想情况下,视图控制器将启动我的数据控制器的异步请求,并向其传递一个完成块,其参数为(a)正在检索的模型对象; (b)NSError

    我将在下面列出一个示例。

  2. 正如您可能从上面推断的那样,我经常也会抽象出Web请求的启动细节以及将响应解析为自己的对象本身(因为数据控制器可能足够复杂,管理缓存,持久存储等)。我通常使用NSOperation子类来执行请求/解析任务(这适用于具有完成块的异步请求;如果UI移动到其他位置,则能够取消挂起的请求,等等)。因此,如果数据控制器得出缓存和/或持久存储不能满足请求的结论,将启动异步请求/解析操作。

  3. 您列出了您已分配给视图控制器的其他几项职责,但也可能最好将其抽象出来:

    • 1.2)处理手势 - 如果手势有点复杂(例如只有水平,从边缘滑动等),我实际上会将手势处理程序子类化,大大简化了视图控制器自己与手势的交互处理程序。

    • 3)自定义UI - 如果UI需要很多自定义,我也经常将相应的视图子类化。特别是UITableViewCellUICollectionViewCell,这可以大大简化视图控制器代码。任何需要任何材料定制的视图通常都可以在视图本身的子类中更优雅地完成。


  4. 示例数据控制器抽象

    所以,我可能会像这样定义一个完成块:

    typedef void(^WeatherRequestCompletion)(WeatherReport *weatherReport, NSError *error);
    

    然后我的数据控制器中可能有一个方法,其界面如下:

    - (WeatherRequest *)requestWeatherWithIdentifier:(CityIdentifier)cityIdentifier completion:(WeatherRequestCompletion)completion;
    

    我的视图控制器会像这样使用它:

    typeof(self) __weak weakSelf = self;
    
    self.weatherRequest = [[WeatherModel sharedController] requestWeatherWithIdentifier:self.cityIdentifier completion:^(WeatherReport *weatherReport, NSError *error) {
        if (error) {
            // handle error
        }
        if (weatherReport) {
            weakSelf.cityLabel.text       = weatherReport.city;
            weakSelf.tempLabel.text       = [weatherReport.temperature stringValue];
            weakSelf.narrativeLabel.text  = weatherReport.narrative;
        }
    }];
    

    视图控制器不应该担心请求的格式化方式以及解析响应的方式(这是我的网络请求NSOperation子类的工作)。视图控制器也不应该过多地参与缓存和/或持久存储逻辑(这是我的数据控制器的工作)。因此,视图控制器应该被提炼为非常合乎逻辑且易于遵循的东西。

    注意,您会注意到我的数据控制器正在返回一个请求对象(对我来说,对于我来说,通常只是一个typedef到NSOperation)。我将让我的视图控制器保持weak对此的引用,以便我可以在需要时轻松取消请求,例如在视图控制器的dealloc中:

    - (void)dealloc
    {
        [_weatherRequest cancel];
    }
    

答案 1 :(得分:1)

大多数情况似乎是典型的ViewController行为。 Apple确实有一个很好的文档,详细描述了MVC架构:http://developer.apple.com/library/ios/documentation/general/conceptual/devpedia-cocoacore/MVC.html

“当模型对象发生更改时(例如,通过网络连接接收新数据),它会通知控制器对象,该对象会更新相应的视图对象。”

这表明您的模型适合处理网络活动和更新。您可以更改的唯一其他方法是在视图中尽可能多地使用UI工作。