oc 基于KVO实现一个promise

作者: 寒枫傲天 | 来源:发表于2017-02-22 16:34 被阅读168次

很多时候作为一个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....

相关文章

  • oc 基于KVO实现一个promise

    很多时候作为一个ioser很羡慕人家用promise来控制异步执行函数。虽然说有promiseKit这种神器 但是...

  • Runtime面试题

    1.oc消息转发流程 2.KVO原理KVO是基于runtime实现的,KVO运用了isa-swizzling将两个...

  • iOS 自定义KVO

    自己实现kvo之前,需要知道iOS系统对kvo的实现。 系统实现kvo的原理 这依赖了OC强大的runtime特性...

  • 通知 /KVO、KVC相关

    如何实现通知机制? KVO ·kvo是OC对观察者设计模式的又一实现 ·APPLE使用了isa混写实现kvo KV...

  • KVO读书笔记

    KVO是什么 KVO 是 OC 对 观察者模式的实现。 KVO提供一种机制,指定一个被观察对象A,...

  • iOS知识点小结

    1.KVO1.1> KVO 简介:KVO 是 OC 观察者设计模式的一种实现.KVO 指定一个被观察的对象的属性,...

  • KVO原理分析

    一、KVO底层实现原理 示例代码: KVO 的实现过程实际上是利用了 OC 的 runtime 机制,当一个实例对...

  • iOS KVO 补充版

    1. 什么是KVO? KVO全称key-value observing; KVO是OC中观察者设计模式的又一个实现...

  • ios-Runtime(运行时)

    利用runtime来实现归档解档 方法交换 俗称 OC的方法欺骗 KVO的实现原理 用runtime来实现KVO...

  • iOS KVO的底层实现原理

    KVO 是 OC 观察者设计模式的一种KVO 的实现依赖于 OC 强大的 RuntimeKVO是Cocoa提供的...

网友评论

    本文标题:oc 基于KVO实现一个promise

    本文链接:https://www.haomeiwen.com/subject/acjmwttx.html