一个快速开发框架:MVVMFramework-Swift
jopen
9年前
MVVMFramework-Swift
https://github.com/lovemo/MVVMFramework
OC版本地址:再看了几篇博客后,总结整理下一个快速开发MVVM框架,分离控制器代码,降低代码耦合
终于再也不用为ViewController中一坨坨tableView和collectionView的烦人代码忧虑了
代码加入了cell自适应高度代码,配合MJExtension,MJExtension,AFNetworking等常用开发框架使用更佳,主要用于分离控制器中的代码,降低代码耦合程度,可以根据自己使用习惯调整代码。欢迎来喷,提issues。
思维流程图示
现在的工程代码结构
模块构建
- 功能模块中的类集合
- Controller - 负责View和ViewModel之间的绑定,另一方面也负责常规的UI逻辑处理。
- View - 用来呈现用户界面
- Model - 用来呈现数据
- ViewModel - 存放各种业务逻辑和网络请求
结构分析
- Handler中BQViewModel抽象出的类集合
- BaseViewModel 声明了一些基本的方法,负责处理一些系统业务逻辑
- XTableDataDelegate 遵守并实现了部分tableView的delegate和dataSource中的一些协议方法
- XTCollectionDataDeleagte 遵守并实现了部分collectionView的delegate和dataSource中的一些协议方法
代码分析
BaseViewModel中代码实现
// ViewModel基类 class BQBaseViewModel: NSObject { weak var viewController: UIViewController? /** * 懒加载存放请求到的数据数组 */ lazy var dataArrayList:NSMutableArray = { return NSMutableArray() }() required override init() { } /** * 返回指定indexPath的item */ func modelAtIndexPath(indexPath: NSIndexPath) -> AnyObject? { return nil } /** * 显示多少组 (当tableView为Group类型时设置可用) */ func numberOfSections() -> Int { return 1 } /** * 每组中显示多少行 (用于tableView) */ func numberOfRowsInSection(section: Int) -> Int { return 0 } /** * 每组中显示多少个 (用于collectionView) */ func numberOfItemsInSection(section: Int) -> Int { return 0 } /** * 分离加载首页控制器内容 (内部使用) */ func getDataList(url: String!, params: [NSObject : AnyObject]!, success: (([AnyObject]!) -> Void)!, failure: ((NSError!) -> Void)!) { } /** * 用来判断是否加载成功,方便外部根据不同需求处理 (外部使用) */ func getDataListSuccess(success: Void -> Void, failure: Void -> Void) { } } extension BQBaseViewModel { class func modelWithViewController(viewController: UIViewController) -> Self? { let model = self.init() model.viewController = viewController return model } }
XTableDataDelegate中部分代码实现
/** * 配置UITableViewCell的内容Block */ typealias TableViewCellConfigureBlock = (NSIndexPath, AnyObject, UITableViewCell) -> Void /** * 选中UITableViewCell的Block */ typealias DidSelectTableCellBlock = (NSIndexPath, AnyObject) -> Void /** * 设置UITableViewCell高度的Block (已集成UITableView+FDTemplateLayoutCell,现在创建的cell自动计算高度) */ typealias CellHeightBlock = (NSIndexPath, AnyObject) -> CGFloat
XTCollectionDataDeleagte中部分代码实现
/** * 配置UICollectionViewCell的内容Block */ typealias CollectionViewCellConfigureBlock = (NSIndexPath, AnyObject, UICollectionViewCell) -> Void /** * 选中UICollectionViewCell的Block */ typealias DidSelectCollectionCellBlock = (NSIndexPath, AnyObject) -> Void /** * 设置UICollectionViewCell大小的Block */ typealias CellItemSize = ( ) -> CGSize /** * 获取UICollectionViewCell间隔Margin的Block */ typealias CellItemMargin = ( ) -> UIEdgeInsets
现在的创建tableView代码
由于用到了UITableView+FDTemplateLayoutCell,现在创建的cell自动计算高度,满足日常开发需求。
/** * tableView的一些初始化工作 */ func setupTableView() { self.table.separatorStyle = .None; // 配置tableView的每个cell let configureCell: TableViewCellConfigureBlock = {(indexPath, obj, cell) -> Void in cell.configure(cell, customObj: obj, indexPath: indexPath) } // 设置点击tableView的每个cell做的一些工作 let selectedBlock: DidSelectTableCellBlock = { [weak self] (indexPath, item) -> Void in if let strongSelf = self { let sb = UIStoryboard(name: "Main", bundle: nil) let vc = sb.instantiateViewControllerWithIdentifier("ViewController2ID") strongSelf.presentViewController(vc, animated: true, completion: nil) print("click row : \((indexPath.row))") } } // 将上述block设置给tableHander self.tableHander = XTableDataDelegate.init(viewModel: BQViewModel(), cellIdentifier: MyCellIdentifier, configureCellBlock: configureCell, didSelectBlock: selectedBlock) // 设置UITableView的delegate和dataSourse为collectionHander self.tableHander?.handleTableViewDatasourceAndDelegate(self.table) }
现在的创建collectionView代码
/** * collectionView的一些初始化工作 */ func setupCollectionView() { // 配置collectionView的每个item let configureCell: CollectionViewCellConfigureBlock = {(indexPath, obj, cell) -> Void in cell.configure(cell, customObj: obj, indexPath: indexPath) } // 设置点击collectionView的每个item做的一些工作 let selectedBlock: DidSelectCollectionCellBlock = {(indexPath, item) -> Void in print("click row : \((indexPath.row))") self.dismissViewControllerAnimated(true, completion: nil) } ; // 配置collectionView的每个item的size let cellItemSizeBlock: CellItemSize = { return CGSizeMake(110, 120) }; // 配置collectionView的每个item的margin let cellItemMarginBlock: CellItemMargin = { return UIEdgeInsetsMake(0, 20, 0, 20) }; // 将上述block设置给collectionHander self.collectionHander = XTCollectionDataDelegate.init(viewModel: BQViewModel2(), cellIdentifier: MyCellIdentifier2, collectionViewLayout: UICollectionViewFlowLayout(), // 可以使用自定义的UICollectionViewLayout configureCellBlock: configureCell, cellItemSizeBlock: cellItemSizeBlock, cellItemMarginBlock: cellItemMarginBlock, didSelectBlock: selectedBlock) // 设置UICollectionView的delegate和dataSourse为collectionHander self.collectionHander?.handleCollectionViewDatasourceAndDelegate(self.collectionView) }
demo效果
- 只需实现加载请求以及配置自定义cell和上述代码,就能轻松实现以下效果,最重要的是代码解耦。
使用方法
- 导入BQViewModel文件,然后在模块代码中新建ViewModel子类,继承BQBaseViewModel类型,实现加载数据等方法。
- 在ViewController中,初始化tableView或者collectionView,根据需要实现block代码,利用XTableDataDelegate或者XTCollectionDat aDelegate的初始化方法将block代码和自己实现的ViewModel类型传递到内部,将会自动根据传入的内容去展现数据。
- 利用xib自定义cell,在 override func configure(cell: UITableViewCell, customObj obj: AnyObject, indexPath: NSIndexPath)方法中根据模型Model内容配置cell展示的数据。
期待
- 如果在使用过程中遇到BUG,希望你能Issues我,谢谢(或者尝试下载最新的代码看看BUG修复没有)
- 如果在使用过程中发现功能不够用,希望你能Issues我,我非常想为这个框架增加更多好用的功能,谢谢
推荐-几篇不错的MVVM学习文章