oc 基于KVO实现一个promise

很多时候作为一个ioser很羡慕人家用promise来控制异步执行函数。
虽然说有promiseKit这种神器 但是总归希望能了解一下promise;


  • 何谓promise
A Promise is a proxy for a value not necessarily known when the promise is created. 
It allows you to associate handlers with an asynchronous action's eventual success value or failure reason.
 This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value,
 the asynchronous method returns a promise to supply the value at some point in the future.
======
pending: initial state, not fulfilled or rejected.
fulfilled: meaning that the operation completed successfully.
rejected: meaning that the operation failed.

这是https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise 的介绍。

  • 作为iOS 开发。兴许对于promise使用场景有限,但是肯定遇到下面的情况
[nettool getData(^(id data){
        // 我还要继续请求根据这个data获取的数据
        [nettool getData(^(id data){
                // 我还要继续请求根据这个data获取的数据
                [nettool getData(^(id data){
                          // 我还要继续请求根据这个data获取的数据
                        [nettool getData(^(id data){
                          // 我还要继续请求根据这个data获取的数据
                                 [nettool getData(^(id data){
                          // 我还要继续请求根据这个data获取的数据
                                      。。。。
                        })
              })
        })
})]

是不是看着很恶心,这就是我们常说的回调地狱。对于写的人来说不觉得,但是对以后某位同事来帮你查bug的时候,我想他会买一把刀吧。

试想一下 如果我们这么写呢?

 [QXPromise promise^(Fullfilled fullfilled,Rejected rejected ){
         [nettool getData(^(id data){

                  resolve(data)
                  // if error 
                   rejected(err)
          })] 
  }].then(^id(id data){
        [nettool getData(^(id data){

                  resolve(data)
                 
          })] 
}).then(^id(id data){
        [nettool getData(^(id data){

                  resolve(data)
                 
          })] 
}).then(^id(id data){
        [nettool getData(^(id data){

                  resolve(data)
                 
          })] 
});

是否觉得眼前一亮呢?

在这里我将会实现这个promise

  • 定义promise的三个状态
/**
   promise状态

 - QXPromiseStatePending:  执行中
 - QXPromiseStateResolved: 完成执行
 - QXPromiseStateRejected: 已拒绝执行
 */
typedef NS_ENUM(NSUInteger, QXPromiseState) {
    QXPromiseStatePending = 0,
    QXPromiseStateFullfilled = 1,
    QXPromiseStateRejected = 2
};

定义block

typedef id (^QXRunBlock) (id value);
typedef void(^QXFullFilledHandler)(id value);
typedef void(^QXErrorBlock)(NSError *error);
typedef QXErrorBlock RejectHandler;
typedef void(^QXPromiseBlock)(ResolveHandler resolve,RejectHandler reject);
typedef void(^ProgressHandler)(double proportion,id value);

实现类

@interface QXPromise : NSObject

@property(nonatomic) id value;

@property(nonatomic) NSError *error;
@property(nonatomic, copy) QXFullFilledHandler resolveBlock;

@property(nonatomic, copy) RejectHandler rejectBlock;

@property(nonatomic, copy) QXPromiseBlock promiseBlock;

@property(nonatomic, copy) RejectHandler catchBlock;

@property(nonatomic, copy) QXRunBlock thenBlock;

+ (QXPromise *)promise:(QXPromiseBlock)block;

我们开始进行梳理
初始化一个promise

- (instancetype)init:(QXPromiseBlock)initBlock {
    self = [super init];
    
    if (self) {
        [self configure];
        self.promiseBlock = initBlock;
    }
    
    self.promiseBlock(self.fullfilledblock,self.rejectedblock)
    return self;
}

- (void)configure {
    if (self) {

        self.state = QXPromiseStatePending;
        [self keepAlive];
        
        __weak QXPromise * wSelf = self;
        self.fullfilledblock = ^(id value){
            __strong QXPromise *sSelf = wSelf;
            if (sSelf.state != QXPromiseStatePending) return;
            
            if ([value isKindOfClass:[QXPromise class]]) {
                if(((QXPromise *)value).state == QXPromiseStatePending) {
                    sSelf.nextPromise = value;
                }
                
                [(QXPromise *) value addObserver:sSelf forKeyPath:@"state" options:NSKeyValueObservingOptionNew context:nil];
            } else {
                sSelf.value = value;
                sSelf.state = QXPromiseStateFullfilled;
                [sSelf loseControl];
            }
        };
        
        
        self.rejectBlock = ^(NSError *error){
            __strong QXPromise *sSelf = wSelf;
            if (sSelf.state != QXPromiseStatePending) return;
    
            sSelf.error = error;

            sSelf.state = QXPromiseStateRejected;
        };
    }
   
}

我们初始化了这个promise。同时对fullfilled和reject 两个blokc初始化。随后将会执行这个promiseblock;

划重点的来了##

先看我们的fullfilledblock

  1. 确定返回参数的类型,如果是promise说明还有链需要调用,
  2. 若是value 说明是返回值该promse也属于调用结束了。进入fullfilled状态,
  3. 是promise对象的 应该对其进行监听。这里使用了kvo。
    4.fullfilled绑定的value会被这个promise持有。这对后面的操作来说很重要。

来看我们的rejectblock
。。。没啥看的。抛出错误 ❌

kvo部分应该属于改promise的核心所在了

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    
    if ([keyPath isEqualToString:@"state"]) {
        QXPromiseState newSate = [change[NSKeyValueChangeNewKey] unsignedIntegerValue];
        
        if (newSate == QXPromiseStateRejected) {
            [object removeObserver:self forKeyPath:@"state"];
            if (self.catchBlock) {
                self.catchBlock([(QXPromise *) object error]);
                self.fullfilledBlock(nil);
            } else {
                self.rejectBlock([(QXPromise *) object error]);
            }
        } else if (newSate == QXPromiseStateFullfilled) {
            [object removeObserver:self forKeyPath:@"state"];
            
            @try {
                id value = nil;
                self.valueKeptForRetry = [(QXPromise *)object value];
                if (self.thenBlock) {
                    value = self.thenBlock([(QXPromise *) object value]);
                } else {
                    value = [(QXPromise *) object value];
                }
                self.thenBlock = nil;
                self.fullfilledBlock(value);
                
            } @catch (NSException *exception) {
                self.rejectBlock(exception);
            } @finally {
                
            }
        }
    }
}

kvo中会抛出错误,或者判断是否需要继续执行。
是否执行通过thenblock来做,这个地方一会再说。
取到thenblock的返回值 作为下一个fullfilledBlock的参数继续执行。

then


- (QXPromise *(^)(QXRunBlock))then {
    __weak QXPromise * wSelf = self;
    return ^QXPromise*(QXRunBlock thenBlock){
        __weak QXPromise *newPromise = nil;
        newPromise = [QXPromise promise:^(fullfilledHandler fullfilled, RejectHandler reject) {
            __strong QXPromise *sSelf = wSelf;
            resolve(sSelf);
        }];
        newPromise.thenBlock = thenBlock;
        return newPromise;
    };

嗯 。。。没了 有时间会写另外一种promise的实现方式。
项目使用还是挺好玩的。

当然还有其他的拓展功能 all catch finally....

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,306评论 19 139
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 5,800评论 0 9
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,896评论 18 399
  • 《围城》里有句名言:“婚姻就像围城,城里的人想出来,而城外的人想冲进去。”突然想起这句话,是因为闺蜜南一告诉我,她...
    三笙与玫瑰阅读 3,034评论 0 0
  • 人群密集的时候就开始惶恐 多了几分动物的感受 家长围在学校门口 如保护幼崽的老猴子 发生了怎么 社会是个大的动物园...
    诗子草皮阅读 1,046评论 0 0