美文网首页
iOS开发 - 链式编程的应用X_Kit

iOS开发 - 链式编程的应用X_Kit

作者: 来者可追文过饰非 | 来源:发表于2019-03-18 11:25 被阅读0次
    1.发现问题

    假如我们写一个UILabel,我们的代码会可能会如下所示

        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
        label.text = @"Hello world!";
        label.textColor = [UIColor whiteColor];
        label.font = [UIFont systemFontOfSize:15];
        label.textAlignment = NSTextAlignmentCenter;
        label.backgroundColor = [UIColor redColor];
        label.layer.cornerRadius = 25;
        label.clipsToBounds = YES;
        [self.view addSubview:label];
    

    这段代码有什么问题呢? 没错!就是非常臃肿,像这些简单的模块如果不加以封装,项目中代码量将会非常多,既不利于阅读,也不利于维护.

    2.初步封装

    在分类中添加方法

    // .h
    + (UILabel *)labelWithText:(NSString *)text textColor:(UIColor *)color font:(UIFont *)font textAlign:(NSTextAlignment)align bgColor:(UIColor *)bgColor cornerRadius:(CGFloat)radius .......;
    
    // .m
    + (UILabel *)labelWithText:(NSString *)text textColor:(UIColor *)color font:(UIFont *)font textAlign:(NSTextAlignment)align bgColor:(UIColor *)bgColor cornerRadius:(CGFloat)radius ....... {
        UILabel *label = [[UILabel alloc] init];
        label.text = text;
        label.textColor = color;
        ...
        return label;
    }
    

    这样的话,我们每次在初始化一个控件的时候,只需要1行代码就可以基本完成问题.但是这样写也有一个新的问题,就是可拓展性的问题.
    -----假如我们只需要设置text和textColor,我们需要写上这么一行,然后后边参数传空
    -----假如我们需要另外设置numOfLines或者其他没有封装到的属性,我们也需要写上这么一行,然后额外设置其他属性

    3.继续优化

    最近再看Masonry源码,其中的链式编程思想对我有很大的启发,我想是否可以采用block的形式设置属性,并用链式编程将他它们链接起来呢?
    说干就干!
    .h文件

    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    typedef UILabel* (^xl_Block)(id);
    
    @interface UILabel (X)
    
    @property (nonatomic, copy, readonly) xl_Block x_text;
    @property (nonatomic, copy, readonly) xl_Block x_font;
    @property (nonatomic, copy, readonly) xl_Block x_textColor;
    @property (nonatomic, copy, readonly) xl_Block x_align;
    
    
    @property (nonatomic, copy, readonly) xl_Block x_numOfLines;
    @property (nonatomic, copy, readonly) xl_Block x_shadowOffset;
    @property (nonatomic, copy, readonly) xl_Block x_lineBreakMode;
    @property (nonatomic, copy, readonly) xl_Block x_attributedText;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    .m文件

    #import "UILabel+X.h"
    #import "XKit.h"
    @implementation UILabel (X)
    
    - (xl_Block)x_text
    {
        xl_Block block = ^UILabel* (NSString *text) {
            self.text = text;
            return self;
        };
        return block;
    }
    
    - (xl_Block)x_font {
        xl_Block block = ^UILabel* (UIFont *font) {
            self.font = font;
            return self;
        };
        return block;
    }
    
    - (xl_Block)x_textColor {
        xl_Block block = ^UILabel* (UIColor *color) {
            self.textColor = color;
            return self;
        };
        return block;
    }
    
    - (xl_Block)x_align {
        xl_Block block = ^UILabel* (NSNumber *align) {
            self.textAlignment = align.integerValue;
            return self;
        };
        return block;
    }
    
    - (xl_Block)x_numOfLines {
        xl_Block block = ^UILabel* (NSNumber *num) {
            self.numberOfLines = num.integerValue;
            return self;
        };
        return block;
    }
    
    - (xl_Block)x_shadowOffset {
        xl_Block block = ^UILabel *(NSValue *value) {
            self.shadowOffset = value.CGSizeValue;
            return self;
        };
        return block;
    }
    
    - (xl_Block)x_lineBreakMode {
        xl_Block block = ^UILabel *(NSNumber *mode) {
            self.lineBreakMode = mode.integerValue;
            return self;
        };
        return block;
    }
    
    - (xl_Block)x_attributedText {
        xl_Block block = ^UILabel *(NSAttributedString *attr) {
            self.attributedText = attr;
            return self;
        };
        return block;
    }
    @end
    

    这样,我们的代码便可以这样写

        UILabel *label = [UILabel new];
        label
        .x_text(@"Hello world!")
        .x_textColor([UIColor whiteColor])
        .x_font([UIFont systemFontOfSize:15])
        .x_align(@(NSTextAlignmentCenter))
        .x_sizeToFit(@(YES));
        
        label
        .x_cornerRadius(@(15))
        .x_clipToBounds(@(YES))
        .x_backgroundColor([UIColor redColor]);
        [self.view addSubview:label];
    

    是不是很神奇😆

    4.项目地址

    具体源码可以去我的github上下载
    前往github
    希望大家多提意见和建议,可以的话给个小星星奖励

    5.存在的问题

    1.以UILabel 和 UIView为例
    写分类方法的时候,我将
    UILabel的属性写到UILabel+X中,其中block返回的为UILabel对象
    UIView的属性写到UIView+X中,其中的block返回的为UIView对象
    所以就会出现例如label.x_backgroundColor([UIColor whiteColor]) 之后再去调用UILabel的属性后报错的情况

    目前暂时的解决方法:写的时候要先写UILabel的属性,再写UIView的属性,例如:

        UILabel *label = [UILabel new];
        label
        .x_text(@"Hello world!")
        .x_textColor([UIColor whiteColor])
        .x_font([UIFont systemFontOfSize:15])
        .x_align(@(NSTextAlignmentCenter))
        .x_sizeToFit(@(YES));
        // 上边为UILabel的属性,下边为父类UIView的属性
        .x_cornerRadius(@(15))
        .x_clipToBounds(@(YES))
        .x_backgroundColor([UIColor redColor]);
        [self.view addSubview:label];
    

    2.以UITableView为例,如果想使用链式及block的形式实现UITableView的代理方法,便会自动设置delegate 和 datasource为当前的tableview,并走UITableView+X中实现的delegate 和 datasource方法,之前设置的delegate 和 dataSource 将会无效,例如:

    UITableView *table = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
        table
        .x_rowHeight(@60)
        .x_sectionHeaderHeight(@0.01)  // 在iOS11之后需要设置该属性,才会走heightForHeader的代理方法
        .x_sectionFooterHeight(@0.01) // 在iOS11之后需要设置该属性,才会走heightForFooter的代理方法
        .x_registerCell([UITableViewCell class], cellID)
        .x_delegate(self)
        .x_dataSource(self)
        // 如果实现了delegate 或者 datasource的block,就会自动设置当前为delegate和datasource为table本身,并走UITableView+X中实现的delegate 和 datasource方法,之前设置的delegate 和 dataSource 将会无效
        .x_viewForHeaderInSection(^UIView * _Nonnull(UITableView * _Nonnull table, NSInteger section) {
            UIView *header = [[UIView alloc] initWithFrame:CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width, 200)];
            header.backgroundColor = [UIColor redColor];
            return header;
        })
        .x_viewForFooterInSection(^UIView * _Nonnull(UITableView * _Nonnull table, NSInteger section) {
            UIView *footer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width, 200)];
            footer.backgroundColor = [UIColor blueColor];
            return footer;
        })
        .x_heightForFooterInSection(^NSInteger(UITableView * _Nonnull table, NSInteger section) {
            return 20;
        })
        .x_heightForHeaderInSection(^NSInteger(UITableView * _Nonnull table, NSInteger section) {
            return 20;
        })
        .x_numofSectionsInTableView(^NSInteger(UITableView * _Nonnull table) {
            return self.dataSource.count;
        })
        .x_numOfRowsInSection(^NSInteger(UITableView * _Nonnull table, NSInteger section) {
            return [self.dataSource[section] count];
        })
        .x_cellForRowAtIndexPath(^UITableViewCell * _Nonnull(UITableView * _Nonnull table, NSIndexPath * _Nonnull indexpath) {
            UITableViewCell *cell = [table dequeueReusableCellWithIdentifier:cellID forIndexPath:indexpath];
            cell.textLabel.text = self.dataSource[indexpath.section][indexpath.row];
            return cell;
        })
        ;
        
        [self.view addSubview:table];
    

    3.后续我们持续更新该框架,感谢大家支持!

    相关文章

      网友评论

          本文标题:iOS开发 - 链式编程的应用X_Kit

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