戳我
戳我
文章目录
  1. Masonry中的应用
  2. 链式编程的Demo

链式编程实践

链式编程是将多个操作, 通过.的形式连接在一起, 形成一句话, 以增强代码的阅读性. 链式编程的核心在于, 方法的返回值必须是返回值是self, 参数为需要操作的值的block. 下面我们来看一下Masonry中链式编程的应用.

Masonry中的应用

Masonry的使用大致如下

UIView *demo = [[UIView alloc] init];
[self.view addSubview:demo];
[demo mas_updateConstraints:^(MASConstraintMaker *make) {
   make.left.equalTo(self.mas_left).offset(16);
   make.centerY.equalTo(self.mas_centerY).offset(0);
   make.width.height.equalTo(@(200));
}];

这里只简单分析一下他链式编程的实现. 我们先看下mas_makeConstraints方法.

- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    block(constraintMaker);
    return [constraintMaker install];
}

这里一共有三步:

  1. 创建一个MASConstraintMaker对象constraintMaker.
  2. 调用block(constraintMaker), 这样在外面我们调用mas_makeConstraints方法里面的make实际就是这里的constraintMaker. 相当于我们在外面调用地方写的控件的约束全部都保存到constraintMaker对象里面了.
  3. 调用[constraintMaker install]方法, 先遍历卸载之前的约束, 再安装新的约束, 最后返回包含所有约束的数组.

下面我们再看一下添加约束的步骤, 以make.width.height.equalTo(@(200))为例.

@implementation MASConstraint
- (MASConstraint *)width {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeWidth];
}

- (MASConstraint *)height {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeHeight];
}

- (MASConstraint * (^)(id))equalTo {
    return ^id(id attribute) {
        return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
    };
}

- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    return [self constraint:nil addConstraintWithLayoutAttribute:layoutAttribute];
}

@end

我们可以发现, widthheight方法的返回值都是MASConstraint对象, 方法内部封装了 一些内部实现, 这样就可以无限的.下去.
equalTo这样的方法需要通过()的方式传参进去, 并且还行要能一直.下去. 通过()的方式传参只有通过block, 想持续.必须返回MASConstraint对象, 所以equalTo的返回值是一个blockMASConstraint * (^)(id)(返回值是self, 并且还有参数).

总结一下核心就是:

  • 把要做的事封装到block, 给外界提供一个返回这个block的方法.
  • 方法返回值必须是block, block的返回值是方法调用者(一般就是self), block的参数是传入的需要操作的内容.

链式编程的Demo

我们以完成一个计算器的Demo为例. 我们新建一个Caculator类来做计算, 实现add方法如下:

@interface Caculator : NSObject

@property (nonatomic, assign) NSInteger result;//结果

//返回值是block(Caculator *(^)(NSInteger number)), 该block的返回值是Caculator*, 参数为NSInteger类型
- (Caculator *(^)(NSInteger number))add;
@end


@implementation Caculator

- (Caculator *(^)(NSInteger number))add {
    return ^Caculator *(NSInteger number) {
        self.result += number;
        return self;
    };
}
@end

要实现类似Masonry的调用方式, 就要再封装一层:

@interface NSObject (Calculator)

+ (NSInteger)makeCaculators:(void(^)(Caculator *make))block;
@end


@implementation NSObject (Calculator)

+ (NSInteger)makeCaculators:(void(^)(Caculator *make))block {
    Caculator *mgr = [[Caculator alloc] init];
    block(mgr);
    return mgr.result;
}
@end

在计算时调用这个方法,创建计算制造者,然后调用传入的block, 并且返回结果.

NSInteger result = [NSObject makeCaculators:^(Caculator *make) {
    make.add(4).multiply(5).minus(4).divide(8).add(13);
}];

完整Demo地址在这里. 这篇循序渐进, 写的也不错.