梳理ReactNative中oc到j(luò)s的數(shù)據(jù)流動(dòng)

以添加CalendarManager為例

.h

#import <React/RCTBridgeModule.h>
#import <React/RCTLog.h>

#import <Foundation/Foundation.h>

@interface CalendarManager : NSObject<RCTBridgeModule>

@end

.m


@implementation CalendarManager

- (instancetype)init {
  if (self = [super init]) {
    
  }
  return self;
}
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
{
  // Date is ready to use!
  NSLog(@"location1-----%@",location);
}
RCT_EXPORT_METHOD(fangshufeng:(NSString *)name testTwo:(NSString *)location)
{
  // Date is ready to use!
  NSLog(@"location3-----%@",location);
}
RCT_REMAP_METHOD(fangshufengJsName,
                 addEvent:(NSString *)name testTwo:(NSString *)location hh:(NSString*)jj) {
  NSLog(@"location4-----%@",location);
}
@end

運(yùn)行xcode,在下面的地方打上斷點(diǎn)

15033061710856.jpg

輸出configJSON,只保留CalendarManager相關(guān)的并且json一下就是

{
    "remoteModuleConfig": [
        [
            "CalendarManager",
            null,
            [
                "addEvent", // 這里對(duì)應(yīng)的就是第一個(gè)方法addEvent:(NSString *)name location:(NSString *)location 下面兩個(gè)分別對(duì)應(yīng)第二第三個(gè)
                "fangshufeng",
                "fangshufengJsName"
            ],
            null,
            null
        ],
        ...
    ]
}

這是在debug環(huán)境的情況下傳的是完整配置信息,而在release環(huán)境下這個(gè)配置信息就只有module信息,而其他的方法信息都是通過(guò)懶加載的形式得到

oc通過(guò)方法將jsonstring傳給js

  [_javaScriptExecutor injectJSONText:configJSON
                  asGlobalObjectNamed:@"__fbBatchedBridgeConfig"
                             callback:onComplete];

js如何接收呢

NativeModules.js

 const bridgeConfig = global.__fbBatchedBridgeConfig;

通過(guò)一個(gè)global的key__fbBatchedBridgeConfig將數(shù)據(jù)給到j(luò)s

let NativeModules : {[moduleName: string]: Object} = {};

可以知道NativeModules本身是一個(gè)對(duì)象

我們?cè)?code>debugger

(bridgeConfig.remoteModuleConfig || []).forEach((config: ModuleConfig, moduleID: number) => {
    // Initially this config will only contain the module name when running in JSC. The actual
    // configuration of the module will be lazily loaded.
    const info = genModule(config, moduleID);
    debugger;
    if (!info) {
      return;
    }

    if (info.module) {
      NativeModules[info.name] = info.module;
    }
    // If there's no module config, define a lazy getter
    else {
      defineLazyObjectProperty(NativeModules, info.name, {
        get: () => loadModule(info.name, moduleID)
      });
    }
  });
}

可以過(guò)濾出CalendarManager如下圖所示

具體看看這個(gè)方法做的事情可以知道每個(gè)item都會(huì)經(jīng)過(guò)genModule方法,先來(lái)看看

function genModule(config: ?ModuleConfig, moduleID: number): ?{name: string, module?: Object} {
  if (!config) {
    return null;
  }

  const [moduleName, constants, methods, promiseMethods, syncMethods] = config;
  invariant(!moduleName.startsWith('RCT') && !moduleName.startsWith('RK'),
    'Module name prefixes should\'ve been stripped by the native side ' +
    'but wasn\'t for ' + moduleName);

  if (!constants && !methods) {
    // Module contents will be filled in lazily later
    return { name: moduleName };
  }

  const module = {};
  methods && methods.forEach((methodName, methodID) => {
    const isPromise = promiseMethods && arrayContains(promiseMethods, methodID);
    const isSync = syncMethods && arrayContains(syncMethods, methodID);
    invariant(!isPromise || !isSync, 'Cannot have a method that is both async and a sync hook');
    const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async';
    module[methodName] = genMethod(moduleID, methodID, methodType);
  });
  Object.assign(module, constants);

  if (__DEV__) {
    BatchedBridge.createDebugLookup(moduleID, moduleName, methods);
  }

  return { name: moduleName, module };
}

這個(gè)又用到了genMethod方法,好吧先來(lái)看看

function genMethod(moduleID: number, methodID: number, type: MethodType) {
  let fn = null;
  if (type === 'promise') {
    fn = function(...args: Array<any>) {
      return new Promise((resolve, reject) => {
        BatchedBridge.enqueueNativeCall(moduleID, methodID, args,
          (data) => resolve(data),
          (errorData) => reject(createErrorFromErrorData(errorData)));
      });
    };
  } else if (type === 'sync') {
    fn = function(...args: Array<any>) {
      return global.nativeCallSyncHook(moduleID, methodID, args);
    };
  } else {
    fn = function(...args: Array<any>) {
      console.log('----', args , 'moduleID:--' +  moduleID , 'methodID:---' + methodID);
      const lastArg = args.length > 0 ? args[args.length - 1] : null;
      const secondLastArg = args.length > 1 ? args[args.length - 2] : null;
      const hasSuccessCallback = typeof lastArg === 'function';
      const hasErrorCallback = typeof secondLastArg === 'function';
      hasErrorCallback && invariant(
        hasSuccessCallback,
        'Cannot have a non-function arg after a function arg.'
      );
      const onSuccess = hasSuccessCallback ? lastArg : null;
      const onFail = hasErrorCallback ? secondLastArg : null;
      const callbackCount = hasSuccessCallback + hasErrorCallback;
      args = args.slice(0, args.length - callbackCount);
      BatchedBridge.enqueueNativeCall(moduleID, methodID, args, onFail, onSuccess);
    };
  }
  fn.type = type;
  return fn;
}

方法分為三種,由oc傳給js的時(shí)候也有體現(xiàn)的這里我們先直接看aync情況的,這里做了三件事情

  1. 定義了一個(gè)接收多個(gè)參數(shù)額方法;
  2. 在參數(shù)列表中取出最后的兩個(gè)作為js的回調(diào);
  3. 最終調(diào)用的是原生的方法這里又引出了另一個(gè)方法BatchedBridge.enqueueNativeCall
enqueueNativeCall(moduleID: number, methodID: number, params: Array<any>, onFail: ?Function, onSucc: ?Function) {
    if (onFail || onSucc) {
      if (__DEV__) {
        const callId = this._callbackID >> 1;
        this._debugInfo[callId] = [moduleID, methodID];
        if (callId > DEBUG_INFO_LIMIT) {
          delete this._debugInfo[callId - DEBUG_INFO_LIMIT];
        }
      }
      onFail && params.push(this._callbackID);
      /* $FlowFixMe(>=0.38.0 site=react_native_fb,react_native_oss) - Flow error
       * detected during the deployment of v0.38.0. To see the error, remove
       * this comment and run flow */
      this._callbacks[this._callbackID++] = onFail;
      onSucc && params.push(this._callbackID);
      /* $FlowFixMe(>=0.38.0 site=react_native_fb,react_native_oss) - Flow error
       * detected during the deployment of v0.38.0. To see the error, remove
       * this comment and run flow */
      this._callbacks[this._callbackID++] = onSucc;
    }

    if (__DEV__) {
      global.nativeTraceBeginAsyncFlow &&
        global.nativeTraceBeginAsyncFlow(TRACE_TAG_REACT_APPS, 'native', this._callID);
    }
    this._callID++;

    this._queue[MODULE_IDS].push(moduleID);
    this._queue[METHOD_IDS].push(methodID);

    if (__DEV__) {
      // Any params sent over the bridge should be encodable as JSON
      JSON.stringify(params);

      // The params object should not be mutated after being queued
      deepFreezeAndThrowOnMutationInDev((params:any));
    }
    this._queue[PARAMS].push(params);

    const now = new Date().getTime();
    if (global.nativeFlushQueueImmediate &&
        (now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS ||
         this._inCall === 0)) {
      var queue = this._queue;
      this._queue = [[], [], [], this._callID];
      this._lastFlush = now;
      global.nativeFlushQueueImmediate(queue);
    }
    Systrace.counterEvent('pending_js_to_native_queue', this._queue[0].length);
    if (__DEV__ && this.__spy && isFinite(moduleID)) {
      this.__spy(
        { type: TO_NATIVE,
          module: this._remoteModuleTable[moduleID],
          method: this._remoteMethodTable[moduleID][methodID],
          args: params }
      );
    } else if (this.__spy) {
      this.__spy({type: TO_NATIVE, module: moduleID + '', method: methodID, args: params});
    }
  }

這個(gè)方法一共做了以下幾件事情:

  1. 判斷如果后面兩個(gè)參數(shù)有回調(diào)的話就會(huì)為每個(gè)回調(diào)生成一個(gè)唯一的ID這里叫做_callbackID,并將js方法裝進(jìn)一個(gè)_callbacks的數(shù)組中;

  2. 這里有個(gè)_queue對(duì)象他的結(jié)構(gòu)如下

        _queue: [Array<number>, Array<number>, Array<any>, number];
        
        在js中分別以`MODULE_IDS` `METHOD_IDS` 和 `PARAMS`來(lái)表示數(shù)組的第0、1、2號(hào)元素,之所以這樣命名是達(dá)到為了見(jiàn)名之意的效果
    

    完成了第一步的_callbackID的映射,在分別吧對(duì)應(yīng)的模塊idmoduleID、方法idmethodID和參數(shù)params分別裝進(jìn)_queue對(duì)應(yīng)的數(shù)組中

    this._queue[MODULE_IDS].push(moduleID);
    this._queue[METHOD_IDS].push(methodID);
    this._queue[PARAMS].push(params);
    
  3. 回調(diào)原生的global.nativeFlushQueueImmediate方法,對(duì)應(yīng)原生的

```
context[@"nativeFlushQueueImmediate"] = ^(NSArray<NSArray *> *calls){
  RCTJSCExecutor *strongSelf = weakSelf;
  if (!strongSelf.valid || !calls) {
    return;
  }
  
  RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"nativeFlushQueueImmediate", nil);
  [strongSelf->_bridge handleBuffer:calls batchEnded:NO];
  RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"js_call");
};

```

值得注意的是這里只是做方法的申明,并沒(méi)有調(diào)用。

那我們?cè)诨氐阶铋_(kāi)始的genModule方法,也就是說(shuō)經(jīng)過(guò)genModule方法以后以我們的CalendarManager來(lái)說(shuō)的話也就是返回一個(gè)下面形式的對(duì)象

{
    name:"CalendarManager",
    {
       addEvent: {
             fn(...){},
             type:"async"
        },
        fangshufeng: {
             fn(...){},
             type:"async"
        },
        fangshufengJsName: {
             fn(...){},
             type:"async"
        }
    }
}

再回到一開(kāi)始的方法

if (info.module) {
      NativeModules[info.name] = info.module;
    }

從而經(jīng)過(guò)一大圈的變換最后得到的結(jié)果就是返回一個(gè)NativeModules對(duì)象,還是以CalendarManager為例,得到的NativeModules的對(duì)象如下

CalendarManager: 
    {
       addEvent: {
             fn(...){},
             type:"async"
        },
        fangshufeng: {
             fn(...){},
             type:"async"
        },
        fangshufengJsName: {
             fn(...){},
             type:"async"
        }
    }

我們自定義的CalendarManager作為了NativeModules的一個(gè)屬性,CalendarManager所對(duì)應(yīng)的方法列表成了CalendarManager屬性
這里只是用CalendarManager為例子來(lái)講的,實(shí)際上最后NativeModules是有很多的類(lèi)似CalendarManager的屬性

15033248335271.jpg

也就是說(shuō)每一個(gè)原生模塊都對(duì)應(yīng)NativeModules一個(gè)屬性

到這里也就說(shuō)完了原生創(chuàng)建一個(gè)模塊到j(luò)s的演變過(guò)程,我們來(lái)總結(jié)一下,當(dāng)我們要?jiǎng)?chuàng)建一個(gè)原生模塊的時(shí)候需要做些什么;

  1. 要繼承<RCTBridgeModule>這個(gè)協(xié)議;

  2. 要在.m中加入RCT_EXPORT_MODULE();還記得之前那個(gè)發(fā)給js的那個(gè)原生模塊的jsonString吧這個(gè)目的其實(shí)是要將當(dāng)前模塊加入配置表中也就是下面的這個(gè)方法

    void RCTRegisterModule(Class moduleClass)
    {
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
        RCTModuleClasses = [NSMutableArray new];
      });
    
      RCTAssert([moduleClass conformsToProtocol:@protocol(RCTBridgeModule)],
                @"%@ does not conform to the RCTBridgeModule protocol",
                moduleClass);
    
      // Register module
      [RCTModuleClasses addObject:moduleClass];
    }
    
  3. 對(duì)于要暴露給js的oc方法需要使用RCT_EXPORT_METHOD這個(gè)宏

    RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
    

    展開(kāi)以后就是下面這個(gè)樣子

    + (NSArray<NSString *> *)__rct_export__300 { 
            return @[@"", 
            @"addEvent:(NSString *)name location:(NSString *)location "]; 
            } 
    - (void)addEvent:(NSString *)name location:(NSString *)location;
    

    到后面要查找方法列表的時(shí)候就是通過(guò)__rct_export__前綴來(lái)查找的,查找的方法如下

            - (NSArray<id<RCTBridgeMethod>> *)methods
{
  if (!_methods) {
    NSMutableArray<id<RCTBridgeMethod>> *moduleMethods = [NSMutableArray new];

    if ([_moduleClass instancesRespondToSelector:@selector(methodsToExport)]) {
      [moduleMethods addObjectsFromArray:[self.instance methodsToExport]];
    }

    unsigned int methodCount;
    Class cls = _moduleClass;
    while (cls && cls != [NSObject class] && cls != [NSProxy class]) {
      Method *methods = class_copyMethodList(object_getClass(cls), &methodCount);

      for (unsigned int i = 0; i < methodCount; i++) {
        Method method = methods[i];
        SEL selector = method_getName(method);
        if ([NSStringFromSelector(selector) hasPrefix:@"__rct_export__"]) {
          IMP imp = method_getImplementation(method);
          NSArray<NSString *> *entries =
            ((NSArray<NSString *> *(*)(id, SEL))imp)(_moduleClass, selector);
          id<RCTBridgeMethod> moduleMethod =
            [[RCTModuleMethod alloc] initWithMethodSignature:entries[1]
                                                JSMethodName:entries[0]
                                                 moduleClass:_moduleClass];

          [moduleMethods addObject:moduleMethod];
        }
      }

      free(methods);
      cls = class_getSuperclass(cls);
    }

    _methods = [moduleMethods copy];
  }
  return _methods;
}

這個(gè)方法做了兩個(gè)事情,一個(gè)是查找已__rct_export__開(kāi)頭的方法,一個(gè)是以__rct_export__方法開(kāi)頭的第一個(gè)參數(shù)為js方法的名稱(chēng)。

  1. 由3可知以這個(gè)宏RCT_EXPORT_METHOD的話默認(rèn)給js的方法名稱(chēng)是參數(shù)的第一位,可以知道都是空的,可是我們最后是需要給js一個(gè)方法一個(gè)名稱(chēng)的這里oc做了默認(rèn)處理了
    - (NSString *)JSMethodName
{
  NSString *methodName = _JSMethodName;
  if (methodName.length == 0) {
    methodName = _methodSignature;
    NSRange colonRange = [methodName rangeOfString:@":"];
    if (colonRange.location != NSNotFound) {
      methodName = [methodName substringToIndex:colonRange.location];
    }
    methodName = [methodName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    RCTAssert(methodName.length, @"%@ is not a valid JS function name, please"
              " supply an alternative using RCT_REMAP_METHOD()", _methodSignature);
  }
  return methodName;
}

也就是如果JSMethodName的長(zhǎng)度為空的話就會(huì)截取第二個(gè)參數(shù)的:以前的字符串作為方法,也就是
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)對(duì)應(yīng)addEvent,RCT_EXPORT_METHOD(fangshufeng:(NSString *)name testTwo:(NSString *)location)對(duì)應(yīng)fangshufeng,那這樣的話問(wèn)題就來(lái)了,萬(wàn)一還有個(gè)這樣的方法RCT_EXPORT_METHOD(fangshufeng:(NSString *)name)按照默認(rèn)的規(guī)則豈不是就和RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)沖突了嗎,rn為了避免這種情況,我們可以使用這個(gè)宏RCT_REMAP_METHOD,也就是這種用法

    RCT_REMAP_METHOD(fangshufengJsName,
                 addEvent:(NSString *)name testTwo:(NSString *)location hh:(NSString*)jj) {
  NSLog(@"location4-----%@",location);
}

這樣的話之前那個(gè)數(shù)組的參數(shù)第一個(gè)值就有值了對(duì)應(yīng)fangshufengJsName

  1. 在研究js源碼的時(shí)候我們發(fā)現(xiàn),js對(duì)參數(shù)的解析是有要注意的地方的,如果原生想要使用js的回調(diào)的話只能放在參數(shù)的后兩位
    RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location action:(RCTResponseSenderBlock)action)
{
  // Date is ready to use!
  NSLog(@"location1-----%@",location);
}

這樣的話就是錯(cuò)的

    RCT_EXPORT_METHOD(addEvent:(NSString *)name   action:(RCTResponseSenderBlock)action location:(NSString *)location)
    {
      // Date is ready to use!
      NSLog(@"location1-----%@",location);
    }

接下來(lái)將要講的是當(dāng)自定義的模塊方法被調(diào)用時(shí)數(shù)據(jù)是如何流動(dòng)的。

首先我們先把CalendarManager用起來(lái)

import  React,{Component} from 'react';
import {
    NativeModules,
    Text,
    TouchableOpacity,
    NativeAppEventEmitter,
    View,
} from 'react-native'

import  FadeInView from './FadeInView'

let CalendarManager = NativeModules.CalendarManager;

export  default  class TestAnimal extends  Component {

    render() {
        return (
            <TouchableOpacity
                 onPress={() => {CalendarManager.fangshufeng('name','ggg')}}
            >
            <FadeInView style={{width: 250, height: 50, backgroundColor: 'powderblue'}}

            >
                <Text style={{fontSize: 28, textAlign: 'center', margin: 10}}>Fading in</Text>
            </FadeInView>
            </TouchableOpacity>
        )
    }

}

運(yùn)行的結(jié)果

15033660664537.jpg

點(diǎn)擊fading in也就是調(diào)用fangshufeng方法,之前我們說(shuō)過(guò)enqueueNativeCall方法只是做方法申明,這個(gè)時(shí)候就是調(diào)用之前定義的方法,在我的這個(gè)工程里面可以debug到,fangshufeng這個(gè)方法的moduleID1,methodID1

15033664429808.jpg

然后debug到enqueueNativeCall

15033665264435.jpg

可以看到最終傳給oc的queue是什么

15033665894650.jpg

如果只看CalendarManager的話當(dāng)你點(diǎn)擊Fading in的時(shí)候傳給oc的queue就是

[[1],[1],[['name','ggg']]]

然后通過(guò)nativeFlushQueueImmediate方法給到oc,會(huì)進(jìn)到下面的這個(gè)方法

- (void)handleBuffer:(NSArray *)buffer
{
  NSArray *requestsArray = [RCTConvert NSArray:buffer];

  NSArray<NSNumber *> *moduleIDs = [RCTConvert NSNumberArray:requestsArray[RCTBridgeFieldRequestModuleIDs]];
  NSArray<NSNumber *> *methodIDs = [RCTConvert NSNumberArray:requestsArray[RCTBridgeFieldMethodIDs]];
  NSArray<NSArray *> *paramsArrays = [RCTConvert NSArrayArray:requestsArray[RCTBridgeFieldParams]];

  int64_t callID = -1;

  if (requestsArray.count > 3) {
    callID = [requestsArray[RCTBridgeFieldCallID] longLongValue];
  }

    // 1
  NSMapTable *buckets = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory
                                                  valueOptions:NSPointerFunctionsStrongMemory
                                                      capacity:_moduleDataByName.count];

    //2
  [moduleIDs enumerateObjectsUsingBlock:^(NSNumber *moduleID, NSUInteger i, __unused BOOL *stop) {
    RCTModuleData *moduleData = self->_moduleDataByID[moduleID.integerValue];
    dispatch_queue_t queue = moduleData.methodQueue;
    NSMutableOrderedSet<NSNumber *> *set = [buckets objectForKey:queue];
    if (!set) {
      set = [NSMutableOrderedSet new];
      [buckets setObject:set forKey:queue];
    }
    [set addObject:@(i)];
  }];

    //3
  for (dispatch_queue_t queue in buckets) {
    dispatch_block_t block = ^{
      NSOrderedSet *calls = [buckets objectForKey:queue];
      @autoreleasepool {
        for (NSNumber *indexObj in calls) {
          NSUInteger index = indexObj.unsignedIntegerValue;
          [self callNativeModule:[moduleIDs[index] integerValue]
                          method:[methodIDs[index] integerValue]
                          params:paramsArrays[index]];
        }
      }
    };
        [self dispatchBlock:block queue:queue];
    }

  _flowID = callID;
}

在需要的解釋的地方做了個(gè)標(biāo)記

  1. 由于下面要用到object->object 所以這里使用map也就是NSMapTable來(lái)保存數(shù)據(jù);
  2. 這個(gè)地方可能有點(diǎn)繞,如果對(duì)數(shù)據(jù)結(jié)構(gòu)不清楚的話比較難以理解,還是以CalendarManager為例子,先來(lái)假設(shè)其他的數(shù)據(jù)如下所示:
    假設(shè)js傳給oc的queue是這個(gè)樣子的
    [
        [38,19,41,41,1], // 最后一個(gè)1表示`CalendarManager`模塊
        [19,1,4,3,1], // 最后一個(gè)1表示addEvent: location: 方法
        [[...],[...],[...],[...],['name','ggg']] //['name','ggg']表示方面方法的入?yún)?    ]

我們通過(guò)斷點(diǎn)來(lái)跟蹤一下數(shù)據(jù)

`modules`
    <__NSArrayI 0x7b048e30>(
    38,
    19,
    41,
    41,
    1
    )
    

buckets

    po buckets
    NSMapTable {
    [10] <OS_dispatch_queue: com.facebook.react.CalendarManagerQueue[0x7b652310]> -> {(
        4
    )}
    [46] <OS_dispatch_queue: com.facebook.react.ShadowQueue[0x7b19cb90]> -> {(
        0,
        2,
        3
    )}
    [47] <null> -> {(
        1
    )}
    }
    po methodIDs
    <__NSArrayI 0x7b048da0>(
    19,
    1,
    4,
    3,
    1
    )
    po paramsArrays
    <__NSArrayI 0x7ee5f7c0>(
    <__NSArray0 0x7a648bd0>(
    
    )
    ,
    <__NSSingleObjectArrayI 0x7b04c8d0>(
    47
    )
    ,
    <__NSSingleObjectArrayI 0x7b04daf0>(
    3
    )
    ,
    <__NSArrayI 0x7ee55570>(
    4,
    3,
    {
        frames =     (
            0,
            "0.008888888888888889",
            "0.03555555555555556",
            "0.08000000000000002",
            "0.1422222222222222",
            "0.2222222222222223",
            "0.3200000000000001",
            "0.4355555555555557",
            "0.5644444444444444",
            "0.6799999999999999",
            "0.7777777777777777",
            "0.8577777777777778",
            "0.9199999999999999",
            "0.9644444444444443",
            "0.9911111111111111",
            1,
            1
        );
        iterations = 1;
        toValue = 1;
        type = frames;
    },
    13
    )
    ,
    <__NSArrayI 0x7b2630e0>(
    name,
    ggg
    )
    

做的事情就是:

遍歷模塊的數(shù)組 -> 在_moduleDataByID取出moduleData -> 以moduleData中的串行隊(duì)列作為key set作為value,而set中裝著的對(duì)應(yīng)的索引,由于module、method、Params都是索引值是一一對(duì)應(yīng)的,這個(gè)索引值即是當(dāng)前module在modules數(shù)組的索引值,也是method、Params的索引值。

  1. 上面已經(jīng)給出了bucket的具體內(nèi)容,循環(huán)后也就是調(diào)用下面的方法
    [self callNativeModule:[moduleIDs[index] integerValue]
                              method:[methodIDs[index] integerValue]
                              params:paramsArrays[index]];
    
    // 具體就是
    [self callNativeModule:1 //可以知道這個(gè)1就是`CalendarManager`
                    method:1 // 這個(gè)1就是表示addEvent: location: 方法
                    params:['name','ggg'] //表示方面方法的入?yún)?                    ];

    //具體上面怎么解析的下面會(huì)做分析

oc拿到數(shù)據(jù)得到模塊名稱(chēng)、方法名稱(chēng)、參數(shù),然后執(zhí)行

最后編輯于
?著作權(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)容

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