美文网首页
iOS MVVM在UITableView中的使用

iOS MVVM在UITableView中的使用

作者: money_ac9e | 来源:发表于2021-08-13 11:31 被阅读0次

    前言

    目前公司升级系统,需要使用MVVM来展示复杂的页面,如详情等
    这里说明 越是复杂的详情 越需要使用UITableView展示
    主要是方便后期维护 我改过几个整个详情页面都适用xib画的 太可怕了

    思路

    1>详情页 肯定有一个UIViewController和Model
    将model转化为需要显示的cell的数量
    在Controller中实现UITableView的代理
    进而展示数据
    2>将model转化为cell的数量 这个步骤写在Controller中 会导致Controller 代码量很大 不好维护 可以创建一个对象完成这个步骤
    3>每个页面都实现UITableView的代理,太复杂了 将UITableView的代理方法封装 方便使用 减少不必要的代码
    4>对于tableview来说 如果在tabelview中写明具体使用某个cell 那封装将没有任何意义
    这里是数组中保存的是model,所有的model都继承自baseModel 使用时从baseModel读取出cell 展示数据,将model传值到cell中
    5>cell和controller的通信 展示数据好说 要是需要传值 怎么处理?
    这里是使用block将数据或者值或者方法传到第2步创建好的对象中
    在从对象中传到controller中

    实现

    1>封装tableview

    需要一个 继承自NSObject 的UITableViewMiddle,主要是提供方法、实现代理、注册cell
    UITableView分为section和row 这里就需要两个model UITableViewSectionModelBase 和 UITableViewCellModelBase 这两个model中都有基础参数 reuseIdentifier 和 rowHeight 用于确定是哪个cell和高度
    使用时 从model中得到具体的cell名 在将model传入cell中,实现数据展示,这里可用KVC、RAC、FBKVOController等各种方法

    下面说下具体的实现
    1.创建UITableViewMiddle 继承自NSObject 主要是为了实现tableview的代理事件
    .h中代码如下

    @interface UITableViewMiddle : NSObject<UITableViewDataSource, UITableViewDelegate>
    
    + (instancetype)tableViewPersenterWithTableView:(UITableView *)tableView
                                   arrSectionModels:(NSArray<__kindof UITableViewSectionModelBase *> *)arrSectionModels;
    
    @property (nonatomic, strong) UITableView *tableView;
    
    @property (nonatomic, strong, readonly) NSArray<__kindof UITableViewSectionModelBase *> *arrSectionModels;
    
    - (void)updateSectionModels:(NSArray<__kindof UITableViewSectionModelBase *> *)arrSectionModels;
    
    @end
    

    可以看到里面有一个类方法,一个控件tableView,一个数组,一个更新方法
    有以上这几个参数就足够了 其他的需要再补充

    .m中的代码主要是分为两部分 其中之一是实现类方法 另一个是实现tableview的代理事件
    这里重点说下 类方法的实现
    众所周知 tableview代理中需要先注册cell ,我们使用的是统一的封装方法 所以注册cell这步骤需要在类方法中实现 这一步还需要考虑 是xib创建 还是纯代码创建
    上代码

    + (instancetype)tableViewPersenterWithTableView:(UITableView *)tableView
                                   arrSectionModels:(NSArray<__kindof UITableViewSectionModelBase *> *)arrSectionModels
    {
        UITableViewMiddle *persenter = [UITableViewMiddle new];
        persenter.tableView             = tableView;
        persenter.arrSectionModels      = arrSectionModels;
        
        [persenter registerCellAndHeaderFooterViews];
        
        return persenter;
    }
    
    - (void)updateSectionModels:(NSArray<__kindof UITableViewSectionModelBase *> *)arrSectionModels
    {
        self.arrSectionModels = arrSectionModels;
        [self registerCellAndHeaderFooterViews];
        [self.tableView reloadData];
    }
    
    - (void)registerCellAndHeaderFooterViews
    {
        self.tableView.dataSource   = self;
        self.tableView.delegate     = self;
        
        [self.arrSectionModels enumerateObjectsUsingBlock:^(__kindof UITableViewSectionModelBase * _Nonnull sectionModel, NSUInteger idx, BOOL * _Nonnull stop) {
            
            if (sectionModel.headerViewModel.headerFooterReuseIdentifier) {
                
                switch (sectionModel.headerViewModel.initMode) {
                    case ClassInitializationMode_Xib:
                    {
                        [self.tableView registerNib:[UINib nibWithNibName:sectionModel.headerViewModel.headerFooterReuseIdentifier bundle:[NSBundle mainBundle]] forHeaderFooterViewReuseIdentifier:sectionModel.headerViewModel.headerFooterReuseIdentifier];
                    }
                        break;
                        
                    case ClassInitializationMode_Code:
                    {
                        
                        [self.tableView registerClass:NSClassFromString(sectionModel.headerViewModel.headerFooterReuseIdentifier) forHeaderFooterViewReuseIdentifier:sectionModel.headerViewModel.headerFooterReuseIdentifier];
                    }
                        break;
                }
            }
            
            if (sectionModel.footerViewModel.headerFooterReuseIdentifier) {
                
                switch (sectionModel.footerViewModel.initMode) {
                    case ClassInitializationMode_Xib:
                    {
                        [self.tableView registerNib:[UINib nibWithNibName:sectionModel.footerViewModel.headerFooterReuseIdentifier bundle:[NSBundle mainBundle]] forHeaderFooterViewReuseIdentifier:sectionModel.footerViewModel.headerFooterReuseIdentifier];
                    }
                        break;
                        
                    case ClassInitializationMode_Code:
                    {
                        
                        [self.tableView registerClass:NSClassFromString(sectionModel.footerViewModel.headerFooterReuseIdentifier) forHeaderFooterViewReuseIdentifier:sectionModel.footerViewModel.headerFooterReuseIdentifier];
                    }
                        break;
                }
            }
            
            [sectionModel.arrCellModels enumerateObjectsUsingBlock:^(UITableViewCellModelBase * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                
                switch (obj.initMode) {
                    case ClassInitializationMode_Xib:
                    {
                        [self.tableView registerNib:[UINib nibWithNibName:obj.reuseIdentifier
                                                                   bundle:[NSBundle mainBundle]]
                             forCellReuseIdentifier:obj.reuseIdentifier];
                    }
                        break;
                    case ClassInitializationMode_Code:
                    {
                        [self.tableView registerClass:NSClassFromString(obj.reuseIdentifier)
                               forCellReuseIdentifier:obj.reuseIdentifier];
                    }
                        break;
                }
                
            }];
            
        }];
    }
    

    2.UITableViewSectionModelBase 基础model 对应tableview的section
    看下代码

    @property (nonatomic, strong) UITableHeaderFooterViewModelBase *headerViewModel;
    @property (nonatomic, strong) NSArray<__kindof UITableViewCellModelBase *> *arrCellModels;
    @property (nonatomic, strong) UITableHeaderFooterViewModelBase *footerViewModel;
    

    3.UITableHeaderFooterViewModelBase 对应tableview的headerView footerView
    看下代码

    @property (nonatomic, assign) BOOL isOpen;
    @property (nonatomic, assign) NSInteger sectionIndex;
    @property (nonatomic, assign) CGFloat   headerFooterViewHeight;
    @property (nonatomic, strong) NSString *headerFooterReuseIdentifier;
    @property (nonatomic, assign) ClassInitializationMode initMode;
    

    4.UITableViewCellModelBase 对象tableview的cell
    看下代码

    @property (nonatomic, strong) NSString * _Nonnull reuseIdentifier;
    
    @property (nonatomic, assign) CGFloat estimatedRowHeight;
    @property (nonatomic, assign) CGFloat rowHeight;
    
    @property (nonatomic, assign) NSInteger index;
    
    @property (nonatomic, assign) ClassInitializationMode initMode;
    
    /// 是否禁止选中,默认否
    @property (nonatomic) BOOL isProhibitSelected;
    
    /**
     设置动态高度 rowHeight
     */
    @property (nonatomic, copy, nullable) CGFloat (^ getCellHeightCallback)(void);
    
    @property (nonatomic, copy, nullable) void (^ reloadTableCell)(void);
    
    /// 刷新cell
    - (void)reloadCell;
    
    + (instancetype _Nonnull )tableViewCellModelBaseWithReuseIdentifier:(NSString *_Nonnull)reuseIdentifier
                                           estimatedRowHeight:(CGFloat)estimatedRowHeight
                                                    rowHeight:(CGFloat)rowHeight
                                                        index:(NSInteger)index;
    
    @property (nonatomic, copy) void (^ _Nullable didSelectRowAtIndexPathCallback)(UITableView * _Nonnull tableView, NSIndexPath * _Nonnull indexPath);
    

    这句封装好了整个tableview
    整体目录如下

    tableview.png
    2>MVVMViewControllerObjc中功能完善

    tableView代理中需要 UITableViewSectionModelBase
    所以 我们最终是需要个数组 里面保存的都是UITableViewSectionModelBase对象

    1.实现类方法

    + (instancetype)loadObjcWithController:(MVVMViewController *)controller
                             withTableView:(UITableView *)tableView
                           withDetailModel:(MVVMDetailModel *)detailModel
    {
        MVVMViewControllerObjc *objc = [[MVVMViewControllerObjc alloc]init];
        objc.controller = controller;
        objc.detailModel = detailModel;
        objc.tableView = tableView;
        
        [objc initializationData];
        
        return objc;
    }
    

    2.实现方法initializationData 里面是添加对应的数据

    - (void)initializationData
    {
        [self.arrSectionModels addObject:[self basicInformationSection]];
        
        self.tableViewMiddle = [UITableViewMiddle tableViewPersenterWithTableView:self.tableView arrSectionModels:self.arrSectionModels];
        [self.tableView reloadData];
    }
    
    - (UITableViewSectionModelBase *)basicInformationSection
    {
        UITableViewSectionModelBase *baseModel = [[UITableViewSectionModelBase alloc] init];
        
        NSMutableArray *arrCellModels = [NSMutableArray array];
        
        ///名字
        {
            MVVMTestViewCellModel *cellModel = [MVVMTestViewCellModel tableViewCellModelWithEstimatedRowHeight:50 rowHeight:50 titleStr:self.detailModel.name];
            [arrCellModels addObject:cellModel];
        }
        
        baseModel.arrCellModels = arrCellModels;
        
        return baseModel;;
    }
    
    3>controller中调用
        self.objc = [MVVMViewControllerObjc loadObjcWithController:self withTableView:self.tableView withDetailModel:self.detailModel];
    

    这样是不是简单一点

    ps:这是我同事写的,被我盗用了....

    链接 https://pan.baidu.com/s/1fItpU-daMhUEjK0_2jeodg 提取码: mwn0

    相关文章

      网友评论

          本文标题:iOS MVVM在UITableView中的使用

          本文链接:https://www.haomeiwen.com/subject/omulbltx.html