MVVM初实践

Author: Charles Zhu
Summary: a sample project practising MVVM

之前已经初步了解了一些MVVM的概念,需要在实践中体会这种设计模式,并理解“响应式”带来的优越性。
考虑到最近一直在做网盘类产品,于是决定:获取网盘的内容,并可以浏览内容。如果是文件夹的话,则可以点击查看内容。这样,就相当于实现了一个小型的文件查看器。
另外需要说明的,这里的网盘其实是一个带有系统的SD卡,自身带有AP,可以无线连接访问。同时,提供了API接口获取相关的数据。

MVVM 的角色分配

视图无疑是用UITableView, 控制器自然选择UITableViewController,自然这里需要建立一个ViewModel来监视一切变化并把这种变化传递给控制器。

已知的VM任务

  1. 获取文件夹列表 VM需要知道当前所在的路径。另外获取到的数据需要重组:比如去掉隐藏文件,进行排序等。这个操作可以封装在某个数据访问层。
  2. cell的点击操作 对于文件,需要把文件内容显示出来(为了方便,这里只对图片文件显示)。

控制器的任务

显示页面,以及点击cell时的页面切换。

VM的内容

  1. UITableViewdataSource dataSource相应的接口需要由VM来实现。在实现cell的时候,cell上的文件名也要通过VM来获取
  2. 数据获取的时机 一般是在VM的信号didBecomeActiveSignal中去注册相应的事件。当事件完成后(获取列表任务),发送更新signal去通知控制器更新页面,因此在控制器中也要注册更新signal收到时相应的事件。整个伪代码逻辑:
    //ViewController
        @weakify(self)
    [self.viewModel.updatedContentSignal subscribeNext:^(id x) {
    @strongify(self);
    [self.tableView reloadData];
    }];
    
    //ViewModel
    self.updatedContentSignal = [[ RACSubject subject] setNameWithFormat:@"%@_MasterVC",self.directory];
    self.flashCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        return [RACSignal defer:^RACSignal *{
            //get content list
    
            //finish data fetching and send signal
    
            [(RACSubject *)self.updatedContentSignal sendNext:nil];
            return nil;
        }];
    }];
    
    @weakify(self)
    [self.didBecomeActiveSignal subscribeNext:^(id x) {
    @strongify(self);
    [self.flashCommand execute:[NSNull null]];
    }];
    

Cell的点击

由于有文件和文件夹的区别,cell无法在storyboard中创建2个push的segue,所以先利用对于文件夹的点击在UITableView的点击delegate事件中进行操作,而文件的点击则通过performSegueWithIdentifier来实现。

总结

总体来说,实践基本按循MVVM的原则来进行,控制器中的内容变得很清爽,基本上只包含对view的控制,和VM的通信则是通过响应式的方式实现的。同时VM中包含了很多数据处理的内容,基本上逻辑的部分都转移到了VM中进行。在这种情况下,一个controller就要配一个VM,不知道会不会又造成VM的臃肿?