美文网首页
FFEasyModel-简介

FFEasyModel-简介

作者: 炒鸡范 | 来源:发表于2017-04-18 15:40 被阅读60次

    基本介绍

    在iOS开发中,我们经常会碰到使用tableview或者collectionview来承接复杂页面展示的情况。面对复杂的页面结构和数据结构,通常会在tableview或者collectionviewdatasourcedelegate中使用大量重复的if..else if..else来描述页面逻辑。当碰到需求变化页面改动时,更是痛苦不堪。

    FFEasyModel就是用来解决这种问题的。他的目标是简化delegatedatasource的逻辑代码,将页面逻辑进行统一的管理,使业务逻辑更加清晰,一目了然。

    基本使用方法

    在PCH中#import "FFEasyModel.h",这将会导入所需要的全部文件,因为我们会在UIView+FFEasyData.h中为UIView扩展一些属性和方法,这是使用FFEasyModel必不可少的.

    1.注册需要使用的cell

    [self.tableView registerClass:[FFStringTableViewCell class] forCellReuseIdentifier:[FFStringTableViewCell ff_identifier]];
    

    可以看到这里使用到了[FFStringTableViewCell ff_identifier],这是在UIView+FFEasyData.h中已经为我们扩展的方法。

    1.创建模型

    - (void)updateDataSource
    {
        //self.data = @[@"基本collection",@"复杂操作collection"];
        self.dataSource = [NSMutableArray array];
        
        //创建section模型 用来管理整个section相关的信息
        FFEasyTableSectionModel *sectionModel = [[FFEasyTableSectionModel alloc] init];
        
        NSMutableArray *cellModels = [NSMutableArray array];
        for (NSInteger i = 0; i < self.data.count; i ++) {
            //创建cell模型
            //这里将这个cell用到的UI、代理对象、数据对象以及简单点击操作方法传递给cellModel
            __weak typeof(self)weakself = self;
            FFEasyTableCellModel *cellModel = [[FFEasyTableCellModel alloc] initWithClassName:NSStringFromClass([FFStringTableViewCell class]) delegate:self data:self.data[i] tapBlock:^{
                [weakself jumpToPage:i];
            }];
            [cellModels addObject:cellModel];
        }
        
        //把cell模型交给section模型
        sectionModel.cellModels = cellModels;
        //把section模型交给section模型数组
        [self.dataSource addObject:sectionModel];
        
        [self.tableView reloadData];
        
    }
    
    

    3.tableview的delegate和datasource

    #pragma mark - tableview delegate & datasource
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return self.dataSource.count;
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return self.dataSource[section].cellModels.count;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return self.dataSource[indexPath.section].cellModels[indexPath.row].cellHeight;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell *cell = [self.dataSource[indexPath.section].cellModels[indexPath.row] cellForTableView:tableView];
        return cell;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        dispatch_block_t block = self.dataSource[indexPath.section].cellModels[indexPath.row].tapBlock;
        if (block) {
            block();
        }
    }
    

    可以看到tableview的delegate和datasource代码已经变得非常简洁,并且可以在多个页面直接复制黏贴使用。

    4.cell中实现相关函数

    @implementation FFStringTableViewCell
    
    - (void)setFf_data:(NSString *)ff_data
    {
        [super setFf_data:ff_data];
        //这里可以做模型赋值,也可以直接调整界面相关元素
        self.textLabel.text = ff_data;
    }
    
    - (void)setFf_delegate:(id)ff_delegate
    {
        //这里可以做代理对象的赋值
        [super setFf_delegate:ff_delegate];
    }
    
    - (void)ff_clear
    {
        //这里可以做一些cell复用前的清理工作
    }
    
    + (CGFloat)ff_viewHeightWithModel:(id)model
    {
        //返回cell的高度
        return 60.0f;
    }
    
    
    @end
    

    通过以上步骤,整个tableview的展示逻辑都被归在了updateDataSource这个方法里。其他人接手代码时也能够清楚地明白当前页面的展示逻辑。

    基本实现原理

    1.UIView+FFEasyData.h

    @interface UIView (FFEasyData)
    
    @property (nonatomic, strong) id ff_data;//用来存储视图的数据对象
    @property (nonatomic, weak) id ff_delegate;//用来存储视图的操作代理对象
    
    
    - (void)ff_clear;//cell重用时的清除多余资源占用动作
    
    + (NSString *)ff_identifier;//cell的重用标记
    
    + (CGFloat)ff_viewHeightWithModel:(id)model;//用来获取tableview情况下的cell高度
    
    + (CGSize)ff_viewSizeWithModel:(id)model;//用来获取collectionview情况下的cell大小
    
    @end
    

    这里为UIView扩展了相关属性是后面简化代码的关键。

    2.FFEasyTableSectionModel.hsection模型

    @interface FFEasyTableSectionModel : NSObject
    
    @property (nonatomic, strong) FFEasyTableHeaderModel *headerModel;//头视图模型
    @property (nonatomic, copy) NSArray<FFEasyTableCellModel *> *cellModels;//cell模型数组
    @property (nonatomic, strong) FFEasyTableFooterModel *footerModel;//脚视图模型
    
    @end
    
    

    创建一个section模型来保存一个section需要的基本元素,header、footer和cell模型。这个section模型会在tableview的delegate和datasource中为tableview提供相关对象模型。

    3.FFEasyTableCellModel.h

    @interface FFEasyTableCellModel : NSObject
    
    @property (nonatomic, strong) NSString *className;//保存了视图类名
    @property (nonatomic, weak) id delegate;//代理对象
    @property (nonatomic, strong) id data;//数据对象
    @property (nonatomic, copy) dispatch_block_t tapBlock;//点击操作
    @property (nonatomic, assign) CGFloat height;//高度 TODO:做高度缓存
    
    //这个方法来生成cell模型 传入所需要的相关数据
    - (instancetype)initWithClassName:(NSString *)className delegate:(id)delegate data:(id)data tapBlock:(dispatch_block_t)tapBlock;
    
    //返回cell视图实例
    - (UITableViewCell *)cellForTableView:(UITableView *)tableView;
    
    //获取cell高度
    - (CGFloat)cellHeight;
    
    @end
    
    

    再看.m中的实现

    @implementation FFEasyTableCellModel
    
    - (instancetype)initWithClassName:(NSString *)className delegate:(id)delegate data:(id)data tapBlock:(dispatch_block_t)tapBlock
    {
        self = [super init];
        if (self) {
            _className = className;
            _delegate = delegate;
            _data = data;
            _tapBlock = tapBlock;
        }
        return self;
    }
    - (UITableViewCell *)cellForTableView:(UITableView *)tableView
    {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.className];
        if (!cell) {
            cell = [[NSClassFromString(self.className) alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:self.className];
        }
        cell.ff_delegate = self.delegate;
        cell.ff_data = self.data;
        return cell;
    }
    
    - (CGFloat)cellHeight
    {
        _height = 0;
        return self.height;
    }
    
    - (CGFloat)height
    {
        if (!_height) {
            //通过UIView+FFEasyData扩展的ff_viewHeightWithModel向cell获取高度
            _height = [NSClassFromString(self.className) ff_viewHeightWithModel:self.data];
        }
        return _height;
    }
    
    
    @end
    

    这样我们很容易地将原本写在tableview的delegate和datasource中的代码,分别交给了cellModel去实现,赋值设置过程和返回高度交给了cell本身去实现。

    更多

    原本FFEasyModel只是一个支持tableview的工具,但是在公司业务不断变化中tableview已经无法继续支持复杂的页面逻辑,因此我扩展了对collectionview的相关支持。同时为了保持界面的流畅性和支持对单个section和cell的刷新,我又增加了FFEasyCollectionModel.h来实现相关插入删除更新动作,避免不断updateDataSource造成性能消耗和页面闪动,提升用户体验。

    未完成的

    collection的header、footer也应该返回Size,我偷了个懒。
    代理设置貌似有点问题。
    。。。

    FFEasyModel DEMO 在这里.

    相关文章

      网友评论

          本文标题:FFEasyModel-简介

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