前言
我们开发过程当中很多时候会对一个对象的属性多次设置参数,比如设置一个UILable和UIButton时候,会多次使用点语法setter和getter属性,步骤繁琐,于是我就想起了SDAutoLayout和Masonry当中使用的链式编程结构,而且现在很多的比较成熟的第三方框架也越来越多的使用这种开发方式。
这种编程方式最大的优点就是一次开发,后面使用都是迅速调用,省去繁琐的多次调用点语法,但也有缺点,初次开发代码量较大,语法复杂。但是对于常用的一些类来说基本是一次开发终生受益。
使用方法
Masonry的使用方法
SDAutoLayout的使用方法
实现原理
通过上面两个例子,我们尝试推测一下大概的结构:
- 链式语法每一次调用都会调用点语法。
- 又因为通常情况下在OC调用方法当中,一般使用中括号来调用,所以可以推测调用的是Block,
- 又因为链式编程的语法是连续调用,并且很多时候是无序的连续调用方法,所以我们能推测出,每次调用返回的应该是这个类的实例对象。
我们先看看上面两个的实现原理
Masonry
- (MASConstraint * (^)(CGFloat))offset {
return ^id(CGFloat offset){
self.offset = offset;
return self;
};
}
SDAutoLayout
typedef SDAutoLayoutModel *(^MarginToView)(id viewOrViewsArray, CGFloat value);//getter方法的返回值
- (MarginToView)leftSpaceToView
{
if (!_leftSpaceToView) {
_leftSpaceToView = [self marginToViewblockWithKey:@"left"];
}
return _leftSpaceToView;
}
- (MarginToView)marginToViewblockWithKey:(NSString *)key
{
__weak typeof(self) weakSelf = self;
return ^(id viewOrViewsArray, CGFloat value) {
SDAutoLayoutModelItem *item = [SDAutoLayoutModelItem new];
item.value = @(value);
if ([viewOrViewsArray isKindOfClass:[UIView class]]) {
item.refView = viewOrViewsArray;
} else if ([viewOrViewsArray isKindOfClass:[NSArray class]]) {
item.refViewsArray = [viewOrViewsArray copy];
}
[weakSelf setValue:item forKey:key];
return weakSelf;
};
}
通过以上我们可以看出,基本和我们之前推测的是一样的:使用点语法、运用Block回调、返回值是调用的实例对象。
我们简单分析一下
以Masonry的方法做例子
- (MASConstraint * (^)(CGFloat))offset {
return ^id(CGFloat offset){
self.offset = offset;
return self;
};
}
以上方法可以看做作为一个getter方法,因为在我们使用点语法的过程当中,这个方法必须是有返回参数,但是无传入参数,所以这个方法正好可以看做是offset这个属性的getter方法来使用,也就是说可以直接用点语法来调用。
应该会有人来发问,offset的参数是怎么传进来的?
.offset(5)当中,(5)是整个Block的参数,并且也是作为Block的参数传出去,因为Block的返回值参数用于从外向内返回参数传递结果,这就是为什么我们从外面传入参数,在内部会得到参数数值的原因。
返回的参数是一个Block,MASConstraint是Block返回值的类型,CGFloat是Block返回参数的类型。以上都是Block的基础用法,要是看的不是很明白,可以看一下我下面的参考文件。
我们分析一下调用过程
- make.left.offset 得到的是一个Block;
- make.left.offset(5) 传入参数之后,执行Block,返回值为MASConstraint的对象,所以之后仍然可以继续调用其他MASConstraint的方法。
使用场景
我觉得使用场景其实很多,看个人需求了,但是我总结的不外乎以下几点:
- 需要取得返回值之后不断的进行下一步运算,比如加减乘除计算器。
- 需要连续设置一个实例的参数,比如设置UILable的属性等,不再需要连篇累牍的多次书写点语法来设置属性。
但是以上总结起来,其实就是需要对一个对象进行连续且重复操作的是时候需要使用链式编程的语法。