iOS链式编程的实现方案

2019-10-17  本文已影响0人  a_只羊

在iOS中,Masonry自动布局库是典型的链式与函数式编程的集中体现。基于函数式编程范式的思想,包装组装对应的功能的同时链式串联组装,整体实现功能组装实现上顺畅自然,方便阅读,更体现了策略者模式的设计优势。
为了达到链式调用的目的,例如(obj.add().muti())的操作,这其中包含以下的重要信息:

  1. 点语法的使用
  2. 链式操作的实现
  3. 链式对象实例以及方法的包装操作

实现点语法调用操作

首先说第一点,在OC中点语法的操作有两种:
1.Blcok调用
2.通过内置属性取值调用(getter
所以我们可以依据第一点实现一个点语法操作,如下:

//声明一个block
@property (nonatomic, copy) void * (^addPushDes)(NSString *parameter);
@property (nonatomic, copy) GCDemoObj * (^addPushID)(NSString *parameter);

//取当前属性
- (void)testBlock{
    GCDemoObj *demoObj = [GCDemoObj new];
    demoObj.addPushDes(@“des”);
    demoObj.addPushID(@“ID”);
}
//声明的实现
- (void (^)(NSString *parameter))addPushDes{
   return ^(NSString *parameter){
        //包装操作的实现在这里写
    }
}

- (void (^)(NSString *parameter))addPushID{
   return ^(NSString *parameter){
        //包装操作的实现在这里写
    }
}

实现链式调用能力

demoObj.addPushDes(@“”);这行代码实际上做了两件事情:

1.取Block
2.调用Block

完成点语法之后,接下来就是如何去将整个操作串联起来,如何去实现一个链式操作组装呢?其实很好理解,就是在调用Block之后,将Block中函数的返回值设置为当前的类对象即可,因为返回对象本身之后,它就能接着进行自身其他的方法调用了,所以Block这一块的返回值是实现链式操作的关键。所以经过改造之后的结果如下:

//声明一个block
@property (nonatomic, copy) GCDemoObj * (^addPushDes)(NSString *parameter);
@property (nonatomic, copy) GCDemoObj * (^addPushID)(NSString *parameter);
//取当前属性
- (void)testBlock{
    GCDemoObj *demoObj = [GCDemoObj new];
    demoObj.addPushDes(@"des").addPushID(@"ID");
}

//声明的实现
- (GCDemoObj * (^)(NSString *parameter))addPushDes{
   return ^GCDemoObj * (NSString *parameter){
        //包装操作的实现在这里写
        
        return self;
    }
}
- (GCDemoObj * (^)(NSString *parameter))addPushID{

   return ^GCDemoObj * (NSString *parameter){
        //包装操作的实现在这里写
        
        return self;
    }
}

实现链式调用的封装操作(Masonry的链式内容方法包装)

以上基本实现了链式操作的功能了,但是并不够完美,通常想要用这个对象还是需要将对象进行一次实例操作,并且实例之后链式调用脱离了当前的实例,能不能两步封成一步操作,在实例的同时设置包装属性设置,完成最终的效果,所以这样的实例操作就来了,在进行一次方法改造:

+ (instancetype)makeDemoObj:(void (^) (GCDemoObj *))settingBlock{   
    GCDemoObj *obj = [GCDemoObj new];
    settingBlock(obj);  //这一步很关键,实现方法设置内容
    return obj;
}

最后

所以实现以上三步更改之后,基本上就实现了一个简单的函数式与链式调用方案,这里为了去除setter属性的操作(屏蔽setter提示操作),可以将包装的属性内容设置为readonly。以下是三步变换之后的操作代码。

//声明一个block
@property (nonatomic, copy, readonly) GCDemoObj * (^addPushDes)(NSString *parameter);
@property (nonatomic, copy, readonly) GCDemoObj * (^addPushID)(NSString *parameter);

+ (instancetype)makeDemoObj:(void (^) (GCDemoObj *make))settingBlock{   
    GCDemoObj *obj = [GCDemoObj new];
    settingBlock(obj);  //这一步很关键,实现方法设置内容
    return obj;
}
//取当前属性
- (void)testBlock{
    GCDemoObj *demoObj = [GCDemoObj new];
    demoObj.addPushDes(@"des").addPushID(@"ID");
}
//声明的实现
- (GCDemoObj * (^)(NSString *parameter))addPushDes{

   return ^GCDemoObj * (NSString *parameter){
        //包装操作的实现在这里写
        return self;
    }
}
- (GCDemoObj * (^)(NSString *parameter))addPushID{
   return ^GCDemoObj * (NSString *parameter){
        //包装操作的实现在这里写
        
        return self;
    }
}

使用的时候就与Masonry的使用方式一样了,如下:

+ (void)useDemo{
    [GCDemoObj makeDemoObj:^(GCDemoObj *make){
        make.addPushDes(@"des").addPushID(@"456");
    }];
}
上一篇 下一篇

猜你喜欢

热点阅读