链式编程

### 背景
最近涉及到画折线图业务,由于以前工程代码用的是AAChartKitLib三方,这次app迭代涉及到修改折线图样式,所以自己看了下这个三方源代码。发现使用时候用的是链式属性赋值,自己研究了下。

### 原理

```
self.aaChartModel= AAChartModel.new
.chartTypeSet(AAChartTypeLine)//图表类型
.titleSet(@"")//图表主标题
.subtitleSet(@"")//图表副标题
.yAxisLineWidthSet(@0)//Y轴轴线线宽为0即是隐藏Y轴轴线
```
该三方使用方法如上所示,使用点语法链式调用给model赋值。先说下原理,之后再慢慢分析。 

其实点语法后面的如.chartTypeSet(AAChartTypeLine)分为两步,第一步是调用对象方法chartTypeSe返回block,第二步在调用这个block传入参数AAChartTypeLine然后内部model的AAChartTypeLine属性开始赋值,再返回model对象本身,经过这一次调用执行其实model就赋值了一个属性,并且返回了该对象本身。由于是返回了该对象本身,所以接下来可以继续利用该对象进行调用对象方法,再次执行block赋值,形成循环,导致可以无限链式调用。

## 代码解析

### 1. 写个测试等价代码来分析   

新建一个TestModel类
```
@interface TestModel : NSObject
@property (assign, nonatomic) NSUInteger age;
- (TestModel *(^)(NSUInteger age))ageSet;


@property (copy, nonatomic) NSString* job;
- (TestModel *(^)(NSString * job))jobSet;
@end

@implementation TestModel
- (TestModel *(^)(NSUInteger age))ageSet {
    return ^(NSUInteger age) {
        self.age = age;
        return self;
    };
}

- (TestModel *(^)(NSString * job))jobSet {
    return ^(NSString * job) {
        self.job = job;
        return self;
    };
}

@end
```

在ViewController类里调用

```
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
  
    TestModel *model = TestModel.new
    .ageSet(32)
    .jobSet(@"work");
    NSLog(@"model = %@",model);
}
@end
```
![image](https://note.youdao.com/yws/public/resource/dffcd69e6f6399e7a56d6c4d3c96f7b4/xmlnote/CD68250A19014435975F4C281CB54968/16152)


这不就实现了链式调用了吗!其实原理就是这样子。我们来分下下。
首先要了解类名可以用点调用类方法。对象可以用点调用对象方法,也可以获取属性。  

1. TestModel.new这是类名在调用类方法,返回一个model对象。
2. .ageSet(32)之后返回的model对象调用该ageSet对象方法,返回一个block。之后执行该block传入参数32,内部给改age属性赋值为32之后返回该model对象。
3.  .jobSet(@"work")和上边一样,首先用刚才赋完age值的model对象调用jobSet对象方法,返回block,之后执行该block传入属性work字串,内部给job属性赋值为work字串,再返回该model对象。
这样经过前两个步骤之后该model的两个属性都赋值完了。


### 2. 简化以上测试代码
这里我们利用宏定义来简化上面测试代码
```
#import <Foundation/Foundation.h>
#define PropStatementAndPropSetFuncStatement(propertyModifier, className, propertyType, propertyName)           \
@property(propertyModifier, nonatomic) propertyType propertyName;                                               \
- (className *(^)(propertyType propertyName))propertyName##Set;                                                 \

#define PropSetFuncImplementation(className, propertyType, propertyName)                                        \
- (className * (^)(propertyType propertyName))propertyName##Set{                                                \
return ^(propertyType propertyName){                                                                            \
self.propertyName  =  propertyName;                                                                             \
return self;                                                                                                    \
};                                                                                                              \
}

NS_ASSUME_NONNULL_BEGIN

@interface TestModel : NSObject
@property (assign, nonatomic) NSUInteger age;
- (TestModel *(^)(NSUInteger age))ageSet;

@property (copy, nonatomic) NSString* job;
- (TestModel *(^)(NSString * job))jobSet;

PropStatementAndPropSetFuncStatement(copy, TestModel, NSString *, name)
PropStatementAndPropSetFuncStatement(copy, TestModel, NSString *, address)
@end


#import "TestModel.h"
@implementation TestModel
- (TestModel *(^)(NSUInteger age))ageSet {
    return ^(NSUInteger age) {
        self.age = age;
        return self;
    };
}

- (TestModel *(^)(NSString * job))jobSet {
    return ^(NSString * job) {
        self.job = job;
        return self;
    };
}

PropSetFuncImplementation(TestModel, NSString *, name)
PropSetFuncImplementation(TestModel, NSString *, address)
@end
```
再次调用测试
![image](https://note.youdao.com/yws/public/resource/dffcd69e6f6399e7a56d6c4d3c96f7b4/xmlnote/2B3FFB1451454E5F9B9F3E2116EC26FE/16180)

好了,到这里以后我们就可以使用宏去简化我们代码了。再次对比三方源代码会发现。它就是这样做的。那以后我们就可以这样进行链式编程了。
特别是当我们封装个控件给别人用时候,该控件可能需要传入很多样式属性,如果我们使用链式定义该属性。那别人调用时候就会显得更加简单。


### 3. 宏定义说明
1. 对于一行显示不下的要用反斜杠(\)来换行。
2. ##两个井号键代表左右有需要拼接的字串。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值