-
链式编程
-
Masonry 打点调用原理
之前一直好奇Masonry 框架是怎样实现的,可以一直打点调用,语法使用起来非常友好,结合其他开发者博客理解了打点调用实现原理,下面用一个计算器实现类来说明一下。
- 准备工作:
创建 CaculatorMaker : NSObject 类
@interface CaculatorMaker : NSObject
// 用于存放计算结果
@property (nonatomic, assign) int result;
@end
1. 平常习惯的写法是这样的:
- (instancetype)add:(int)num{
self.result = self.result + num;
return self;
}
在外部调用:
CaculatorMaker *make = [CaculatorMaker new];
int result = [[[[make add:10] add:20] add:30] result] ;
可以看到如果调用计算次数过多,代码可读性很差,解决办法:参考Masonry 写法试一下。
2. 模仿 Mansonry风格写一下
首先如果Mansonry 点进库里看的话,可以看到他的点语法是通过 block 来实现的,此处来模仿一下:
(1)定义一个简单的无参无返回的block调用
.h 文件声明:
- (void(^)())add
.m 方法中实现:
-(void (^)())add{
return ^(){
NSLog(@"block 调用啦");
};
}
外界调用:
CaculatorMaker *make = [CaculatorMaker new];
(1)NSObject *objc = make.add;
这时候断点看一下 objc 类型:
po objc
<__NSGlobalBlock__: 0x102a8e0b0>
可以清楚的看到他是一个 block 类型,因此我直接调用block
make.add(); 就可以看到上面在定义block 时候的打印
“block 调用啦”
至此打点调用语法已经说明完毕,总结一下就是:
声明一个 get 方法,返回的是一个 block,外界调用block。
(2)点语法有了,那么他又是如何实现计算的呢?
在刚才block的基础上我们需要传一个参数
.h 文件声明:
- (void(^)(int))add;
.m 方法中实现:
-(void (^)(int))add{
return ^(int num){
self.result = self.result + num;
NSLog(@"block 调用, result==%d", self.result);
};
}
外界调用:
CaculatorMaker *make = [CaculatorMaker new];
make.add(10);
make.add(20);
make.add(30);
打印如下:
block 调用, result==10
block 调用, result==30
block 调用, result==60
此时已初步完成打点调用完成计算;但是存在两个问题:
(1)计算结果只在 CaculatorMaker 内部,我在外界调用时候不能直接拿到计算结果;
(2)无法像Masonry那样可以连续打点调用,此处每计算一次就得调用一次方法。
为解决上面两个问题,显然我在计算完成的同时需要拿到 make 对象,计算结果就是 make对象的 result 属性,有了make对象我就可以继续打点调用。
在刚才add方法的基础上我返回一个有返回值的block,这个block的返回值就是 make对象,如下:
.h 文件声明:
- (CaculatorMaker* (^)(int))add;
.m 方法中实现:
-(CaculatorMaker* (^)(int))add{
return ^(int num){
self.result = self.result + num;
NSLog(@"block 调用, result==%d", self.result);
return self;
};
}
外界调用:
CaculatorMaker *make = [CaculatorMaker new];
NSObject *objc = make.add(10).add(20).add(30);
此时查看 objc 类型
po objc
<CaculatorMaker: 0x608000018830>
可以看到是 CaculatorMaker 类型的一个对象,此时我可以通过他的 result属性来获取计算结果,那么最终我在外界调用计算方法并且拿到计算结果就是这样的:
int result = make.add(10).add(20).add(30).result;
至此连续 Mansonry 连续打点调用实现的基本原理已经说明完毕,结合上面的小 Demo 总结一下就是:
- 通过block 代码块去保存一段代码,此处是计算过程代码;
- block 是一个有参数又返回值的block,参数就是我们需要参与计算值的,返回值是 计算器构造对象 make,有了返回值make对象,方便我们进行下一个计算。
扩展一下,如果我们想在任意一个类中都可以方便的调用计算方法的话,可以通过分类来实现,代码如下:
#import <Foundation/Foundation.h>
@class CaculatorMaker;
@interface NSObject (Caculator)
+ (void)add:(void(^)(CaculatorMaker *make))block;
@end
#import "NSObject+Caculator.h"
#import "CaculatorMaker.h"
@implementation NSObject (Caculator)
+ (void)add:(void(^)(CaculatorMaker *))block{
CaculatorMaker *make = [CaculatorMaker new];
block(make);
}
@end
外界调用时候就是这样的:
[NSObject add:^(CaculatorMaker *make) {
int result = make.add(5).add(6).add(18).result;
NSLog(@"result___%d",result);
}];
如有不对的地方,欢迎大家指正
网友评论