oc 基于KVO實(shí)現(xiàn)一個(gè)promise

很多時(shí)候作為一個(gè)ioser很羨慕人家用promise來(lái)控制異步執(zhí)行函數(shù)。
雖然說(shuō)有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 開(kāi)發(fā)。興許對(duì)于promise使用場(chǎng)景有限,但是肯定遇到下面的情況
[nettool getData(^(id data){
        // 我還要繼續(xù)請(qǐng)求根據(jù)這個(gè)data獲取的數(shù)據(jù)
        [nettool getData(^(id data){
                // 我還要繼續(xù)請(qǐng)求根據(jù)這個(gè)data獲取的數(shù)據(jù)
                [nettool getData(^(id data){
                          // 我還要繼續(xù)請(qǐng)求根據(jù)這個(gè)data獲取的數(shù)據(jù)
                        [nettool getData(^(id data){
                          // 我還要繼續(xù)請(qǐng)求根據(jù)這個(gè)data獲取的數(shù)據(jù)
                                 [nettool getData(^(id data){
                          // 我還要繼續(xù)請(qǐng)求根據(jù)這個(gè)data獲取的數(shù)據(jù)
                                      。。。。
                        })
              })
        })
})]

是不是看著很惡心,這就是我們常說(shuō)的回調(diào)地獄。對(duì)于寫(xiě)的人來(lái)說(shuō)不覺(jué)得,但是對(duì)以后某位同事來(lái)幫你查bug的時(shí)候,我想他會(huì)買(mǎi)一把刀吧。

試想一下 如果我們這么寫(xiě)呢?

 [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)
                 
          })] 
});

是否覺(jué)得眼前一亮呢?

在這里我將會(huì)實(shí)現(xiàn)這個(gè)promise

  • 定義promise的三個(gè)狀態(tài)
/**
   promise狀態(tài)

 - QXPromiseStatePending:  執(zhí)行中
 - QXPromiseStateResolved: 完成執(zhí)行
 - QXPromiseStateRejected: 已拒絕執(zhí)行
 */
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);

實(shí)現(xiàn)類(lèi)

@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;

我們開(kāi)始進(jìn)行梳理
初始化一個(gè)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;
        };
    }
   
}

我們初始化了這個(gè)promise。同時(shí)對(duì)fullfilled和reject 兩個(gè)blokc初始化。隨后將會(huì)執(zhí)行這個(gè)promiseblock;

劃重點(diǎn)的來(lái)了##

先看我們的fullfilledblock

  1. 確定返回參數(shù)的類(lèi)型,如果是promise說(shuō)明還有鏈需要調(diào)用,
  2. 若是value 說(shuō)明是返回值該promse也屬于調(diào)用結(jié)束了。進(jìn)入fullfilled狀態(tài),
  3. 是promise對(duì)象的 應(yīng)該對(duì)其進(jìn)行監(jiān)聽(tīng)。這里使用了kvo。
    4.fullfilled綁定的value會(huì)被這個(gè)promise持有。這對(duì)后面的操作來(lái)說(shuō)很重要。

來(lái)看我們的rejectblock
。。。沒(méi)啥看的。拋出錯(cuò)誤 ?

kvo部分應(yīng)該屬于改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中會(huì)拋出錯(cuò)誤,或者判斷是否需要繼續(xù)執(zhí)行。
是否執(zhí)行通過(guò)thenblock來(lái)做,這個(gè)地方一會(huì)再說(shuō)。
取到thenblock的返回值 作為下一個(gè)fullfilledBlock的參數(shù)繼續(xù)執(zhí)行。

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;
    };

嗯 。。。沒(méi)了 有時(shí)間會(huì)寫(xiě)另外一種promise的實(shí)現(xiàn)方式。
項(xiàng)目使用還是挺好玩的。

當(dāng)然還有其他的拓展功能 all catch finally....

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,533評(píng)論 19 139
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,041評(píng)論 0 9
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,637評(píng)論 18 399
  • 《圍城》里有句名言:“婚姻就像圍城,城里的人想出來(lái),而城外的人想沖進(jìn)去。”突然想起這句話,是因?yàn)殚|蜜南一告訴我,她...
    三笙與玫瑰閱讀 461評(píng)論 0 0
  • 人群密集的時(shí)候就開(kāi)始惶恐 多了幾分動(dòng)物的感受 家長(zhǎng)圍在學(xué)校門(mén)口 如保護(hù)幼崽的老猴子 發(fā)生了怎么 社會(huì)是個(gè)大的動(dòng)物園...
    詩(shī)子草皮閱讀 165評(píng)論 0 0

友情鏈接更多精彩內(nèi)容