React Native - iOS Native 回調(diào)

( Native 方法理解為 iOS/Android 原生代碼 )
在真實的使用場景中,不僅僅只是調(diào)用下Native的方法,還需要對結(jié)果進行處理,Native處理完之后返回結(jié)果再回調(diào)會JavaScript中進行操作和處理。
這樣就需要使用JavaSctipt的回調(diào)函數(shù),對結(jié)果進行處理。在React Native中Object-c有兩種方式的回調(diào):RCTReponseSenderBlockPromises。

1.RCTReponseSenderBlock

在JavaScript和Object-C的參數(shù)列表,有一類參數(shù)叫做RCTReponseSenderBlock對應JavaScript的Function,這個就是JavaScript調(diào)用Object-C的Callback(回調(diào)函數(shù))。

RCTReponseSenderBlock是在RCTBridgeModule.h定義的block.
完整的定義:

typedef void (^RCTResponseSenderBlock)(NSArray *response);

RCTReponseSenderBlock定義個一個Object-C Bridge的操作,返回給JavaScript一個callback的方法。

他的參數(shù)是一個NSArray。其中第一個參數(shù)是error代表著錯誤信息,如果沒有錯誤傳入null,后面的參數(shù)傳入自定義的內(nèi)容。
具體實例:
先給UIAlertView添加兩個按鈕,在點擊按鈕之后使用RCTResponseSenderBlock返回JavaScript。
先實現(xiàn)UIAlertViewDelegate

@interface RNIOSAlert : NSObject<RCTBridgeModule,UIAlertViewDelegate>
@end

定義一個變量用來保存參數(shù):

@implementation RNIOSAlert{
  RCTResponseSenderBlock _alertCallback;
}
@end

在clickedButtonAtIndex方法中處理結(jié)果并調(diào)用回調(diào)函數(shù):

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    switch (alertView.tag) {
        case 0:
            if (buttonIndex == 0) {
                _alertCallback(@[@"取消"]);
            }else{
                _alertCallback(@[[NSNull null],@"確定"]);
            }
            break;
        default:
            break;
    }
}

最后定義帶有回調(diào)參數(shù)的Native方法:(把 alertView 放在主線程中顯示,否則會卡頓,一段時間后才能顯示出)

RCT_EXPORT_METHOD(showAlertViewAndMsg:(NSString *)message Callback:(RCTResponseSenderBlock) alertCallback){
    _alertCallback = alertCallback;
    dispatch_sync(dispatch_get_main_queue(), ^{
        UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"React Native" message:message delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"繼續(xù)", nil];
        alert.tag = 0;
        [alert show];
    });
}

最在JavaScript中調(diào)用Native方法,并處理回調(diào):

_alertCallback() {
    RNIOSAlert.showAlertAndCallback(function (err, datas) {
        if (err) {
            console.warn('err', '已取消');
        } else {
            console.warn('data', '請繼續(xù)');
        }
    });
}

每次關(guān)閉UIAlertView都可以看到JavaScript處理的結(jié)果。

2.Promises

Promises是ES6中的特性,它的目的是統(tǒng)一為JavaScript提供異步編程的接口,避免Callback地獄,解決了Callback的層層嵌套。更加容易的對異步操作進行控制。詳解參考:React Native - Promise 對象
在React Native中對Promises有很完善的支持,調(diào)用Object-C 的Native方法的時候,也可以Promise的方式讓代碼執(zhí)行從Object-C 回到JavaScript中。
先看Promises的兩個狀態(tài)。

Resolve和Reject是Promise的兩種狀態(tài),表示已解決和已拒絕,

  • Resolve是已解決的執(zhí)行結(jié)果,會觸發(fā)then操作
  • Reject是已拒絕的執(zhí)行結(jié)果,會觸發(fā)catch操作
    在Object-C與之相對應的是:RCTPromiseResolveBlockRCTPromiseRejectBlock,兩個都是定義好的Object-C bridge。

RCTPromiseResolveBlock的實現(xiàn):

typedef void (^RCTPromiseResolveBlock)(id result);

以id為參數(shù),當然傳參必須是Object-c和JavaScript定義好的參數(shù)。
RCTPromiseRejectBlock的實現(xiàn):

typedef void (^RCTPromiseRejectBlock)(NSString *code, NSString *message, NSError *error);

RCTPromiseRejectBlock使用了NSError,還可以傳入自定義的code以及message。

 NSError * error =[NSError errorWithDomain:@"test" code:0 userInfo:nil];
使用Promise實現(xiàn)回調(diào)

首先要定義兩個變量用來保存參數(shù):

@implementation RNIOSAlert{
    RCTPromiseResolveBlock _resolveBlock;
    RCTPromiseRejectBlock _rejectBlock;
}

在定義提供給JavaScript調(diào)用的Native函數(shù):


RCT_REMAP_METHOD(alertUsePromise,resolve:(RCTPromiseResolveBlock)resolve
                 reject:(RCTPromiseRejectBlock)reject){
    _resolveBlock = resolve;
    _rejectBlock = reject;
    
    dispatch_sync(dispatch_get_main_queue(), ^{
        UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"React Native " message:@"使用Promise實現(xiàn)回調(diào) alertUsePromise" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"繼續(xù)", nil];
        alert.tag = 1;
        [alert show];
    });
}

這里使用RCT_REMAP_METHOD宏定義Native,他的第一個參數(shù)是方法名,后面的參數(shù)是方法的實現(xiàn),在JavaScript調(diào)用Promise時并不需要在方法名中體現(xiàn)。
處理結(jié)果并使用回調(diào):

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    if (buttonIndex == 0) {
        NSError * err=[NSError errorWithDomain:@"test" code:0 userInfo:nil];
        _rejectBlock(@"0",@"cancel",err);
    }else{
        _resolveBlock(@[@"成功"]);
    }
}

JavaScript中調(diào)用該方法:

_alertUsePromise() {
     RNIOSAlert.alertUserPromise().then((datas)=> {
         console.warn('data', datas);
     }).catch((err)=> {
         console.warn('err', err);
     });
 }

這里的then處理的是Resovle狀態(tài)的結(jié)果,而catch處理的是Reject狀態(tài)的結(jié)果。
也可以使用async/await實現(xiàn)

async  _alertPromise() {
     try {
         var datas = await RNIOSAlert.alertUserPromise();
         console.warn('data', datas);
     } catch (e) {
         console.warn('err', e);
     }
 }

async/await是兩個關(guān)鍵詞,用來把Promises的思想融入到語言本身。使用他們就不再需要寫catch這樣的偽同步的代碼,直接使用try/catch/return這樣的關(guān)鍵詞就可以了.
Promises對于回調(diào)的使用很便利,盡量避免了JavaScript的回調(diào)地獄。

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

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

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