iOS-block的妙用:链式编程(经典应用:Masonry)

iOS开发当中有一个很特殊的存在,这个特殊就是block。在OC当中实现某一个功能都是一个响应对象调用一个响应方法,简而言之就是Target-Action。

以UIButton为例:

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];

UIButton的事件就是一个响应对象和一个响应方法之间的一一映射。

与UIButton这种不同,block则不一样,其根本不需要响应对象,如下:

    void (^LogString)(NSString *string) = ^(NSString *string) {
        NSLog(@"这是一个用来打印log的block,需要打印的字符串为:%@", string);
    };
    
    LogString(@"12345");

block的使用无非是以下三个步骤:

1.block的声明。上述代码中的void (^LogString)(NSString *string就是将void (^)(NSString *string)声明成一个叫LogString的block
2.block的实现。上述代码中'='后面的便是block的实现,包含了参数与返回值
3.block的调用。上述代码中的LogString(@"12345")就是对block的调用

今天小编就来说说block的另外一项应用:链式编程

说到链式编程最经典的应用便是Masonry了,以下便是Masonry的简单代码:

    [self.nicknameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.leading.top.equalTo(view).priorityHigh();
    }];

其中可以看到对于make这个MASConstraintMaker对象的设置是以一系列的点语法来实现的

当然,这个leadingtop也是很容易实现的,无非就是以系列的get方法而已。但是后面的equalTo(view)priorityHigh()是什么鬼?我们点进去:

Masonry源码

这个时候可以看到equalTo方法的返回值是一个block,而equalTo里面则是一个block的声明,并且将这个block给return了

如此我们在调用equalTo(view)的时候经历了以下步骤:

1.调用equalTo方法的对象是MASConstraint,equalTo方法里面声明了一个block和block的实现
2.MASConstraint对象调用equalTo方法实际上是返回了一个block,这个block的返回值还是MASConstraint对象
3.步骤2获取到一个block,这个block参数是一个id类型的数据,那么equalTo后面的view参数实际上就作为block的参数了,这也就实现了一个block的调用
4.因为block的返回值是MASConstraint对象,所以经历步骤3之后的值实际上还是MASConstraint,调用priorityHigh()就又回到了步骤1

说来说去是不是绕糊涂了?实际上这无非就是block的声明,block的实现与block的实现这三个步骤的另外一种变体。

接下来我们依据上面总结的Masonry的步骤来对UILabel实现链式编程:

1.声明一个UILabel的分类,如下:

UILabel的分类

2.初始化UILabel的方法声明。在UILabel+Additions.h里声明一个叫label的方法,这个方法没有参数,返回值是一个block,这个block的返回值是一个UILabel对象,block的参数是CGRect的结构体。

/**
  * 初始化label,此方法是类方法且没有参数
  * 此方法的返回值是一个block
  * 这个block参数为一个CGRect的参数
  * 返回值还是UILabel对象,用来实现链式编程
 */
+ (UILabel *(^)(CGRect frame))label;

3.初始化UILabel的方法实现。在UILabel+Additions.m实现label方法,最主要是实现block,这个在block里实现UILabel的创建,并将这个block返回,如下:

+ (UILabel * _Nonnull (^)(CGRect))label {
    // 声明并实现一个block,并返回
    return ^(CGRect frame) {
        // 根据传过来的frame参数初始化UILabel,并返回
        return [[UILabel alloc] initWithFrame:frame];
    };
}

同理,设置UILabel的text和textColor也是如此,以下便是代码:
UILabel+Additions.h进行方法的声明:

// 对象方法
- (UILabel *(^)(NSString *title))title;
- (UILabel *(^)(UIColor *titleColor))titleColor;

UILabel+Additions.m对方法进行实现:

- (UILabel * _Nonnull (^)(NSString * _Nonnull))title {
    return ^(NSString *title) {
        self.text = title;
        // 返回self就可以了
        return self;
    };
}

- (UILabel * _Nonnull (^)(UIColor * _Nonnull))titleColor {
    return ^(UIColor *titleColor) {
        self.textColor = titleColor;
        // 返回self就可以了
        return self;
    };
}

应用代码:

    UILabel *label = UILabel.label(CGRectMake(100, 100, 200, 50)).
                     title(@"链式编程的应用").
                     titleColor([UIColor greenColor]);
    label.backgroundColor = [UIColor redColor];
    [self.view addSubview:label];

效果:


效果图

最后打个广告,个人第三方库:
UDUserDefaultsModel:NSUserDefaults的改进方案
YIIFMDB:直接操作Model进行增删改查,数学运算等,且sql语句易于管理

你可能感兴趣的:(iOS-block的妙用:链式编程(经典应用:Masonry))