理解Object-c链式编程

    首先理解什么是链式编程:链式编程,主要通过点‘.’来连接不同的函数调用 (这么定义,我也不清楚这么定义对不对,感觉这个定义怪怪得,将就这么理解算了)。但是oc语法特性,通过点操作连接不同的函数调用尤其还需要给调用函数传入参数并不是那么容易的一件事,首先来看一下:几种编程思想(链式编程、响应式编程、函数式编程) - phxiang的博客 - CSDN博客

oc 语言链式(函数式)编程代表有Masonry,PromiseKit他们的共性是 1、点连接无参数方法或属性。2、返回对象是相同的实例对象或是能返回实例对象的block方法。

图1

上图是masonry的一个应用,方法top 、left 、and 等,都是返回MASConstraint实例对象且不需要传入参数的方法。

图2

方法equalTo,是一个带返回值是MASConstraint实例对象的block,这样,当我们传入参数时就会触发block执行并返回MASConstraint实例对象,这样链式结构得以延续。

图3

认识完在oc结构上是如何实现链式结构的,下面我们分析一下如何使用promiseKit实现链式结构的:

图4

关于promiseKit内部的实现原理,请参考PromiseKit原理篇,弄清楚promisekit原理以后,我个人觉得,每次想让链式结构的值往下传递,还需要传入一个新的Anypromise对象,利用block块往下传递,感觉代码上并不是很“对称”的结构,PromiseKit 只是 Promise 设计模式的一种实现方式,并不能为我们的 app 带来任何”看得到“的好处,而仅仅是为了满足我们对“代码美学”的追求,那么为了解决这种美学的问题,尝试使用promise的结构改进一下代码。如下,封装了一个MyPromise类,使用first类方法创建一个MyPromise对象,需要执行的代码块放在一个first方法的参数block内,如下先展示使用范例 ,after()使用GCD_After模拟异步耗时操作;

图5

在then实例方法中,衔接的所有then方法中的block都会被收集起来放在一个数组中对block强引用防止其被释放,因为在收集完所有then.block之前暂时不触发block执行。

图6

当衔接完所有的then.block和first.block以及catchError的block,然后使用start方法触发first.block,当获取到值时通过储存的then.block数组依此触发相应的blocks,并把值相互传递

当first块的block获取到需要的值时且无异常数据,通过执行excuteThenBlock吧值传个下一个将要触发的block执行,且剩下的then.block是通过递归往下执行并依此传递值的,数组中的block执行完成之后会被立即移除释放:

Mypromise的demo地址

如有意见或建议可留言交流,若小弟有错误或不足之处望指出更正,互相交流学习。PromiseKit的功能远不止解决异步嵌套问题,还有类似GCD中dispatch_group的线程依赖等功能。此处的Mypromise仅仅是展示函数链式编程思想的demo,有兴趣的可以作为练手学习。

另外附上源码:

===============================================================

```

#import  <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@class MyPromise;

typedefvoid(^CatchErrBlock)(NSError*err);

typedefvoid(^PassBlock)(idobj);

typedefvoid(^Adapter)(iddata,PassBlockpass);

typedefvoid(^FirsBlock)(PassBlockpass);

typedefMyPromise*(^__FirsBlock)(FirsBlockfirst);

@interfaceMyPromise :NSObject

/** 首先使用firstblock创建 MyPromise对象*/

+(MyPromise*)first:(FirsBlock)block;

@property (nonatomic,class ,copy ,readonly) __FirsBlock first;

/** then方法延续链接 */

@property (nonatomic ,copy ,readonly) MyPromise*(^then)(Adapter adapter);

/** 错误接收 */

@property(nonatomic,copy,readonly)MyPromise*(^catchError)(CatchErrBlockerrBlock);

/** 开始执行启动 */

-(void)start;

@end

NS_ASSUME_NONNULL_END

===============================================================

#import "MyPromise.h"

@interface MyPromise ()

@property (nonatomic , strong) FirsBlock firstBlock;

@property (nonatomic , strong) CatchErrBlock errorBlock;

@property (nonatomic , strong) NSMutableArray *adapterBlocks;

@end

@implementation MyPromise

-(instancetype)init {

    if(self== [superinit]) {

        self.adapterBlocks= [[NSMutableArrayalloc]init];

    }

    return self;

}

+(MyPromise*)first:(FirsBlock)block {

    MyPromise*promise = [[MyPromisealloc]init];

    promise.firstBlock= block;

    returnpromise;

}

+(__FirsBlock)first {

    return^(FirsBlockfirst){

        MyPromise*promise = [[MyPromisealloc]init];

        promise.firstBlock= first;

        returnpromise;

    };

}

-(MyPromise*_Nonnull(^)(Adapter_Nonnull))then {

    __weak typeof(self) weakSelf = self;

    return^(Adapteradapter){

        if(adapter) [weakSelf.adapterBlocksaddObject:adapter];

        returnweakSelf;

    };

}

-(MyPromise*_Nonnull(^)(CatchErrBlock_Nonnull))catchError {

    __weak typeof(self) weakSelf = self;

    return^(CatchErrBlockerrBlock){

        if(errBlock) weakSelf.errorBlock= errBlock;

        returnweakSelf;

    };

}

-(void)start {

    FirsBlock block = self.firstBlock;

    PassBlockpass = ^(iddata){

        /** 为保持MyPromise生命周期在异步环境下延长,此处使用强引用 */

        if([dataisKindOfClass:[NSErrorclass]]) {

            [selfexcuteErrorBlock:data];

        }else{

            [selfexcuteThenBlock:data];

        }

    };

    block(pass);

}

-(void)excuteThenBlock:(id)data {

    Adapter adapter = self.adapterBlocks.firstObject;

    PassBlockpass = ^(idnewData){

        /** 为保持MyPromise生命周期在异步环境下延长,此处使用强引用 */

        if([newDataisKindOfClass:[NSErrorclass]]) {

            [selfexcuteErrorBlock:newData];

        }else{

            [selfexcuteThenBlock:newData];

        }

    };

    if(adapter) {

        [self.adapterBlocksremoveObject:adapter];

        adapter(data ,pass);

    }

}

-(void)excuteErrorBlock:(NSError*)error {

    CatchErrBlock errBlock = self.errorBlock;

    if(errBlock) {

        errBlock(error);

    }

}

@end

```

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 今天是妈妈去医院产检的日子,从这周开始,我们就需要一周去一次医院直到你出生。今天在医院你还蛮乖的,没有使劲...
    auraro2016阅读 138评论 0 0
  • 问题背景: 在Go端开启协程并发请求java端的同一个接口,java端返回给Go端的数据会经常变化。比如: 第一次...
    caoxinyiyi阅读 184评论 0 0
  • 想写下这一份记录,没有多大的与众不同,但是对我来说,是一份感触。 今天是我的同事LRX生日,首先祝他生日快...
    就叫我小鱼儿吧阅读 328评论 0 0
  • 共修讨论,我更多的看见了自己! 当A在分享自己守时,其他人因为按照自己的想法导致整体上的时间拖延时,我看见自己在过...
    西红柿的小姑娘阅读 172评论 0 2
  • 上学的时候班上有一位同学学习极其刻苦,无论如何都不会错过一个知识点下课之后就会尾随着老师追问着十万个为什么,倘若老...
    李子木LZM阅读 325评论 0 1