LuaView SDK第二版设计插件化理解(二)

LuaView SDK第二版设计插件化理解(二)

第一篇提到了MILExporter类,及它的相关的Api,下面看一下它里面的具体实现。

- (void)reg:(lua_State *)L clazz:(const char *)clazzName constructor:(const char *)constructorName cfunc:(lua_CFunction)cfunc name:(const char *)luaName 注册key到Lua虚拟机的全局表。 传入了className,constructorName。以className为key,具体的闭包为value进行写入。具体代码如下。
        + (void)reg:(lua_State *)L clazz:(const char *)clazzName constructor:(const char *)constructorName cfunc:(lua_CFunction)cfunc name:(const char *)luaName
      
      {
      
          NSAssert(mm_CharPointIsNotNULL(clazzName), @"The class must not be nil!");
      
          NSAssert(mm_CharPointIsNotNULL(luaName), @"The lua name of class must not be nil!");
      
          lua_checkstack(L, 12);
         
          // 把native类名压栈
          lua_pushstring(L, clazzName);
          // 是否为属性压栈。这个暂时没用到
          lua_pushboolean(L, NO); // 不是属性
          // 把初始化方法名称压栈。如果没有的话则走默认的
          lua_pushstring(L, mm_CharPointIsNotNULL(constructorName) ? constructorName : "init");
          // 设置closure的upValue 出栈相应的元素,闭包压栈
          lua_pushcclosure(L, cfunc, 3);
           // 设置闭包到全局表
          lua_setglobal(L, luaName);
      
      }
  • 这个文件的一个核心函数。void mm_lua_openlib (lua_State *L, const char *libname, const struct mm_lua_objc_method *l, int nup) { 注册实例方法到元表和注册类方法到类对应的表。

    void mm_lua_openlib (lua_State *L, const char *libname,
                         const struct mm_lua_objc_method *l, int nup) {
      // 如果libname存在。则相当于注册类方法。
        if (libname) {
            int size = mm_libsize(l);
            /* check whether lib already exists */
            luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);
            lua_getfield(L, -1, libname);  /* get _LOADED[libname] */
            if (!lua_istable(L, -1)) {  /* not found? */
                lua_pop(L, 1);  /* remove previous result */
                /* try global variable (and create one if it does not exist) */
                if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL)
                    luaL_error(L, "name conflict for module " LUA_QS, libname);
                lua_pushvalue(L, -1);
                lua_setfield(L, -3, libname);  /* _LOADED[libname] = new table */
            }
            lua_remove(L, -2);  /* remove _LOADED table */
            lua_insert(L, -(nup+1));  /* move library table to below upvalues */
        }
        // 上面的过程相当于在LUA_GLOBALSINDEX 表中获取libname对应的表
        for (; l->l_mn; l++) {
            NSCAssert(mm_CharPointIsNotNULL(l->clz), @"The class name must not be nil!");
            NSCAssert(l->func!=NULL, @"The C function must not be NULL!");
            int extraCount = 0;
            // 类名压栈
            lua_pushstring(L, l->clz); // class
            // bool 属性压栈
            lua_pushboolean(L, l->isProperty);
            if (l->isProperty) {
                NSCAssert(mm_CharPointIsNotNULL(l->setter_n), @"The method name must not be nil!");       // 为属性则setter_n和getter_n 字符串压栈
                lua_pushstring(L, l->setter_n); // setter
                NSCAssert(mm_CharPointIsNotNULL(l->getter_n), @"The method name must not be nil!");
                lua_pushstring(L, l->getter_n); // getter
                extraCount = 4;
            } else {
                NSCAssert(mm_CharPointIsNotNULL(l->mn), @"The method name must not be nil!");      
                //否则则 selector名称压栈
                lua_pushstring(L, l->mn); // selector
                extraCount = 3;
            }
            int i;
            for (i=0; i<nup; i++)  /* copy upvalues to the top */
                lua_pushvalue(L, -(nup+extraCount));
            // 将相应数量的元素 出栈 +  存储上面压栈的值 +  相应的闭包压栈 +
            lua_pushcclosure(L, l->func, (nup+extraCount));
            // 找到 -(nup+2) 这个位置上面的表,设置l->l_mn为key,栈顶元素为value 写入表。
            lua_setfield(L, -(nup+2), l->l_mn);
        }
        // 栈中移除相应数量的元素
        lua_pop(L, nup);  /* remove upvalues */
    }
    

    下面来看下非常核心的Lua与native的通讯部分,刘旭对原来的通讯方式进行完全的改变。这是LuaViewSDK优化最核心的部分。

  • 上面一直提到我们自己构建了结构体对象。我们映射到Lua的只是这个结构体,映射到lua的全部类方法和对象方法都可以通过这个结构体的MMLua_Method 表示。Lua 去掉用userdata方法,原本通过各个单独的方法调用,现在改为全部都路由到一个C的Api里面,然后在这个Api里面进行消息的分发。下面看下具体的结构体。

    struct mm_lua_objc_method ;
    typedef struct mm_lua_objc_method *MMLua_Method;
    struct mm_lua_objc_class;
    typedef struct mm_lua_objc_class *MMLua_Class;
    
    typedef struct mm_lua_objc_method{
        const char *l_mn;      /* Object-C method name in lua*/
        const char *mn;       /* Object-C method name */
        const char *clz;      /* Object-C class name */
        BOOL isProperty;      /* It's YES if property method*/
        const char *setter_n;   /* Object-C getter method name*/
        const char *getter_n;   /* Object-C setter method name */
        lua_CFunction func;     // 元表对应的func。注册进去的都是func。
    }mm_lua_objc_method;
    
    typedef struct mm_lua_objc_class{
        const  char *pkg;  // package name 
        const  char *clz;  // 类名
        const  char *l_clz;  ///* Object-C class name in lua */
        const char *l_type; /* its type of Object-C class in lua  */
        BOOL isRoot; /* is root function,it should be YES if no base class. */
        const char *supreClz; /* base Object-C class */
        BOOL hasConstructor; /* it should be NO if static class. */
        MMLua_Method methods; /* Object-C method */
        MMLua_Method clz_methods; /* Object-C class method */
        // 初始化函数的描述
        struct mm_lua_objc_method constructor; /* Object-C constructor method */
        
    }mm_lua_objc_class;

下面以 LUA_EXPORT_VIEW_PROPERTY(image, “lua_setImage:”, “lua_image”, MMGraphicButton) 为例。看下具体这个宏定义为我们做了什么。连续点击进去可以发现这个宏最终会我们生成mm_lua_objc_method 这个结构体的一个实例。{image,NULL,MMGraphicButton,YES,”lua_setImage”,”lua_image”,mm_lua_router_method};

  • 此时我们再去查看发现所有的Lua去调用对象方法实际都会路由到我们的mm_lua_router_method中,然后通过这个方法再去生成相应的Invocation 进行invoke调用。我们来具体看下mm_lua_router_method具体做了什么。
    int mm_lua_router_method (lua_State *L) {
       NSCAssert(L, @"The lua state must not be null!");
       // class 首先获取Class
       Class clazz = mm_lua_resolveClass(L);
       // 同理在closure的上值中获取是否为Property
       BOOL isProperty = mm_lua_resolveIsProperty(L);
       // 获取SEL。 如果非属性则直接在上值中获取Sel名称转为SEL
       SEL selector = isProperty ? mm_lua_resolveGetterOrSetter(L) : mm_lua_resolveSelector(L);
       // 方法的调用。
       return mm_lua_call_objc_method(L, selector, clazz);
    }
    
    Class mm_lua_resolveClass (lua_State *L) {
       NSCAssert(L, @"The lua state must not be null!");
       NSCAssert(lua_isstring(L, lua_upvalueindex(1)), @"The first upvalue must be a string of class name!");
       // 通过伪索引 去获取Closure中的上值。
       NSString *clazzString = [NSString stringWithUTF8String:lua_tostring(L, lua_upvalueindex(1))];
       NSCAssert(clazzString && clazzString.length > 0, @"The class name must not be nil!");
       // 将上值存储的string转成Class。上面的openLib方法涉及到了上值的存储。会存储到生成的Closure的upValue数组中。具体的闭包调用的时候在Lua虚拟机的ci的func拿到func,此时为TValue对象,通过TValue找到Closure。
       return NSClassFromString(clazzString);
    }
    // 在上值中获取是否为Property.
    BOOL mm_lua_resolveIsProperty (lua_State *L) {
       NSCAssert(L, @"The lua state must not be null!");
       NSCAssert(lua_isboolean(L, lua_upvalueindex(2)), @"The first upvalue must be a string of selector name!");
       return lua_toboolean(L, lua_upvalueindex(2));
    }
    //  同理通过Lua栈中参数的个数获取是get还是set方法。然后通过上值将String转成Selector
    SEL mm_lua_resolveGetterOrSetter (lua_State *L) {
       NSCAssert(L, @"The lua state must not be null!");
       int selIdx = [MILExporter isLuaCallGetter:L] ? 4 : 3; // setter's index is 3, getter's index is 4
       return mm_lua_resolveSelectorAtIndex(L, selIdx);
    }
    
  • 上面提到了mm_lua_call_objc_method 下面来看下到底做了什么。
     int mm_lua_call_objc_method (lua_State *L, SEL selector, Class<MILEntityClassProtocol> clazz) {
         NSCAssert(L, @"The lua state must not be null!");
         // 在栈底获取Userdata对象并进行类型判断。返回userdata->object对象
         id targetObj = [MILExporter targetOnLuaCall:L class:clazz];
         // 重置LuaCore
         mm_lua_resetLuaCore(L, clazz);
         // 进行真实的方法的调用。
         return mm_lua_call_objc(L, targetObj, selector, NO);
     }
     
     /*
             1. 通过SEL获取方法签名
             2. 通过方法签名生成NSInvocation
             3. 设置Invocation的SEL,target,参数
             4. 执行invocation的invoke的操作
             5. 通过invocation的returnType 确定返回值的个数
     **/
     int mm_lua_call_objc (lua_State *L, id target, SEL selector, BOOL isclass) {
         NSCAssert(L, @"The lua state must not be null!");
         NSCAssert(target, @"The target must not be nil!");
         // 获取方法前面通过SEL
         NSMethodSignature *sig = [target methodSignatureForSelector:selector];
         // 确定方法前面中参数的个数
         NSUInteger argsCount = [sig numberOfArguments] - 2;
         // Lua堆栈中个数
         int l_argsCount = [MILExporter numOfArgsOnLuaCallIn:L];
     //    NSCAssert(argsCount==l_argsCount, @"The number of parameters does not match!");
         // 通过方法签名生成NSInvocation 对象
         NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
         // 设置target
         [invocation setTarget:target];
         // 设置SEL
         [invocation setSelector:selector];
         // 后续是参数的设置
         NSMutableArray *retainArray = [NSMutableArray arrayWithCapacity:argsCount];
         // retain invocation中的target和参数
         [invocation retainArguments];
         for (int i = 2; i <= argsCount + 1; i++) {
             int argIdx = i;
             int stackIdx = i;
             MMTypeConvertorErr success = mm_setInvocationArgByLua(invocation, argIdx, L, stackIdx, retainArray, !isclass);
             switch (success) {
                 case MMTypeConvertorUndef:
                     lua_settop(L, 0);
                     lua_pushstring(L, "Undefined parameter type");
                     return 1;
                 case MMTypeConvertorTypeErr:
                      lua_settop(L, 0);
                     lua_pushstring(L, "An error occurred about the parameter type");
                     return 1;
                 default:
                     break;
             }
         }
         // invocation的调用。
         [invocation invoke];
         return mm_pushInvocationReturnToLua(invocation, L);
     }
    
     // 下面具体看一下setArgument: atIndex:的过程
     
     int mm_setInvocationArgByLua(NSInvocation *invocation, int index, lua_State *L, int stackID, NSMutableArray *retainArray, BOOL hasTarger4Block) {
         // 通过方法前面获取指定位置参数的描述const char* 
         const char* type = [invocation.methodSignature getArgumentTypeAtIndex:index];
         if (type){
             switch (mm_typeOfObjc(type)) {
                 case MM_OBJCType_BOOL: {
                     // Lua 栈相应位置拿到值
                     BOOL value = lua_toboolean(L, stackID);
                     // 设置到invocation相应的位置
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_class: {
                     if (lua_isstring(L, stackID)) {
                         Class clazz = NSClassFromString(lv_paramString(L, stackID));
                         [invocation setArgument:&clazz atIndex:index];
                     }
                     return 0;
                 }
                 case MM_OBJCType_block: {
                     if (lua_isfunction(L, stackID)) {
                         MILBlock *block = nil;
                         if (hasTarger4Block) {
                             block = [[MILBlock alloc] initWithTarget:invocation.target luaCore:LV_LUASTATE_VIEW(L) index:stackID];
                         } else {
                             block = [[MILBlock alloc] initWithLuaCore:LV_LUASTATE_VIEW(L) index:stackID];
                         }
                         MILCallback callback = [^(id result, BOOL keepAlive){
                             [block callWithParam:result];
                         } copy];
                         [retainArray addObject:callback];
                         // 设置callback到指定位置
                         [invocation setArgument:&callback atIndex:index];
                     }
                     return 0;
                 }
                 case MM_OBJCType_SEL: {
                     if (lua_isstring(L, stackID)) {
                         SEL selector = NSSelectorFromString(lv_paramString(L, stackID));
                         [invocation setArgument:&selector atIndex:index];
                     }
                     return 0;
                 }
                 case MM_OBJCType_id: {
                     id nativeObject = nil;
                     if (hasTarger4Block) {
                         // lua对象转native对象
                         nativeObject = mm_lua_tonativeobj(L, stackID, invocation.target);
                     } else {
                         nativeObject = mm_lua_tonativeobj(L, stackID, nil);
                     }
                     [invocation setArgument:&nativeObject atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_char: {
                     char value = lua_tonumber(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_uchar: {
                     unsigned char value = lua_tonumber(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_short: {
                     short value = lua_tonumber(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_ushort: {
                     unsigned short value = lua_tonumber(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_int: {
                     int value = lua_tonumber(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_uint: {
                     unsigned int value = lua_tonumber(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_long: {
                     long value = lua_tonumber(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_ulong: {
                     unsigned long value = lua_tonumber(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_llong: {
                     long long value = lua_tonumber(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_ullong: {
                     unsigned long long value = lua_tonumber(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_float: {
                     float value = lua_tonumber(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_double: {
                     double value = lua_tonumber(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_char_ptr: {
                     char *value = lua_touserdata(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_void_ptr: {
                     void *value = lua_touserdata(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_const_char_ptr: {
                     const char *value = lua_touserdata(L, stackID);
                     [invocation setArgument:&value atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_rect: {
                     CGRect orig_rect = mm_lua_tocgrect(L, stackID);
                     [invocation setArgument:&orig_rect atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_size: {
                     CGSize orig_size = mm_lua_tocgsize(L, stackID);
                     [invocation setArgument:&orig_size atIndex:index];
                     return 0;
                 }
                 case MM_OBJCType_point: {
                     CGPoint orig_point = mm_lua_tocgpoint(L, stackID);
                     [invocation setArgument:&orig_point atIndex:index];
                     return 0;
                 }
                 default: {
                     NSInteger value = 0;
                     NSCAssert(value, @"Undefined parameter type!");
                     [invocation setArgument: &value atIndex:index];
                     LVError(@"Undefined parameter type!");
                     return 1; // 参数类型不支持
                 }
             }
         }
         NSCAssert(NO, @"An error occurred about the parameter type!");
         return 2; // 获取参数类型失败
     }
     
     /**
      获取oc数据类型 mm_typeOfObjc
      */
     MM_Objc_Type mm_typeOfObjc(const char *type) {
         switch (type[0]) {
                 // id类型
             case _C_ID: //#define _C_ID       '@'
                 // 则返回Block
                 if (type[1] == _C_UNDEF) {    '?'
                     return MM_OBJCType_block;
                 }
                 return MM_OBJCType_id;
             case _C_CLASS: //#define _C_CLASS    '#'
                 return MM_OBJCType_class;
             case _C_SEL:  //#define _C_SEL      ':'
                 return MM_OBJCType_SEL;
             case _C_CHR:  //#define _C_CHR      'c'
                 return MM_OBJCType_char;
             case _C_UCHR: //#define _C_UCHR     'C'
                 return MM_OBJCType_uchar;
             case _C_SHT:  //#define _C_SHT      's'
                 return MM_OBJCType_short;
             case _C_USHT: //#define _C_USHT     'S'
                 return MM_OBJCType_ushort;
             case _C_INT:  //#define _C_INT      'i'
                 return MM_OBJCType_int;
             case _C_UINT: //#define _C_UINT     'I'
                 return MM_OBJCType_uint;
             case _C_LNG:  //#define _C_LNG      'l'
                 return MM_OBJCType_long;
             case _C_ULNG: //#define _C_ULNG     'L'
                 return MM_OBJCType_ulong;
             case _C_LNG_LNG: //#define _C_LNG_LNG  'q'
                 return MM_OBJCType_llong;
             case _C_ULNG_LNG: //#define _C_ULNG_LNG 'Q'
                 return MM_OBJCType_ullong;
             case _C_FLT: //#define _C_FLT      'f'
                 return MM_OBJCType_float;
             case _C_DBL: //#define _C_DBL      'd'
                 return MM_OBJCType_double;
             case _C_BOOL: //#define _C_BOOL     'B'
                 return MM_OBJCType_BOOL;
             case _C_VOID: //#define _C_VOID     'v'
                 return MM_OBJCType_void;
             case _C_CHARPTR: //#define _C_CHARPTR  '*'
                 return MM_OBJCType_char_ptr;
             case _C_STRUCT_B: { //#define _C_STRUCT_B '{' 结构体
                 // #define mm_strcmp(a, b) (strcmp((a), (b)) == 0)
                 if (mm_strcmp(type, @encode(CGRect))) {
                     return MM_OBJCType_rect;
                 } else if (mm_strcmp(type, @encode(CGSize))) {
                     return MM_OBJCType_size;
                 } else if (mm_strcmp(type, @encode(CGPoint))) {
                     return MM_OBJCType_point;
                 }
                 return MM_OBJCType_struct;
             }
             case _C_PTR: { //#define _C_PTR      '^'
                 if (type[1] == _C_ID) { ? 
                     return MM_OBJCType_id_ptr;
                 }  else if (type[1] == _C_STRUCT_B) {
                     return MM_OBJCType_struct_ptr;
                 }  else if (mm_strcmp(type, @encode(void *))) {
                     return MM_OBJCType_void_ptr;
                 }
                 //TODO: 待支持其他类型
                 return MM_OBJCType_ndef;
             }
             case _C_CONST: { //#define _C_CONST    'r' 常量
                 if (mm_strcmp(type, @encode(const char *))) {
                     return MM_OBJCType_const_char_ptr;
                 }
                 //TODO: 待支持其他类型
                 return MM_OBJCType_ndef;
             }
             default:  //#define _C_UNDEF    '?'
                 return MM_OBJCType_ndef;
         }
     }
    

上面提到的各种type_VOID等 实际对应了一张表在runtime.h中。对应了所有的参数的类型对应的字符串

#define _C_ID       '@'
#define _C_CLASS    '#'
#define _C_SEL      ':'
#define _C_CHR      'c'
#define _C_UCHR     'C'
#define _C_SHT      's'
#define _C_USHT     'S'
#define _C_INT      'i'
#define _C_UINT     'I'
#define _C_LNG      'l'
#define _C_ULNG     'L'
#define _C_LNG_LNG  'q'
#define _C_ULNG_LNG 'Q'
#define _C_FLT      'f'
#define _C_DBL      'd'
#define _C_BFLD     'b'
#define _C_BOOL     'B'
#define _C_VOID     'v'
#define _C_UNDEF    '?'
#define _C_PTR      '^'
#define _C_CHARPTR  '*'
#define _C_ATOM     '%'
#define _C_ARY_B    '['
#define _C_ARY_E    ']'
#define _C_UNION_B  '('
#define _C_UNION_E  ')'
#define _C_STRUCT_B '{'
#define _C_STRUCT_E '}'
#define _C_VECTOR   '!'
#define _C_CONST    'r'

下面看下Lua端调用以上方法返回部分。也就是调用方法后,相应的native对象需要转为相应的lua支持的对象压栈。

int mm_pushInvocationReturnToLua(NSInvocation* invocation, lua_State* L) {
    // 通过方法签名拿到返回参数的字符串描述
    const char *type = [invocation.methodSignature methodReturnType];
    if (type){
        // 上面已经说了。具体看上面runtime的一个表去对应
        switch (mm_typeOfObjc(type)) {
            case MM_OBJCType_void:
                return 0;
            case MM_OBJCType_BOOL: {
                BOOL result = 0;
                // 传入参数的地址。方法内部会根据传入的指针会修改相应内存的值
                [invocation getReturnValue: &result];
                lua_pushboolean(L, result);
                return 1;
            }
            case MM_OBJCType_class: {
                Class clazz = nil;
                [invocation getReturnValue:&clazz];
                if (clazz) {
                    lua_pushstring(L, NSStringFromClass(clazz).UTF8String);
                } else {
                    lua_pushnil(L);
                }
                return 1;
            }
            case MM_OBJCType_SEL: {
                SEL sel = nil;
                [invocation getReturnValue:&sel];
                if (sel) {
                    lua_pushstring(L, NSStringFromSelector(sel).UTF8String);
                } else {
                    lua_pushnil(L);
                }
                return 1;
            }
            case MM_OBJCType_id: {
                void *result = nil;
                [invocation getReturnValue:&result];
                mm_lua_pushnativeobj(L,(__bridge id)result);
                return 1;
            }
            case MM_OBJCType_char: {
                char result = 0;
                [invocation getReturnValue: &result];
                lua_pushnumber(L, result);
                return 1;
            }
            case MM_OBJCType_uchar: {
                unsigned char result = 0;
                [invocation getReturnValue: &result];
                lua_pushnumber(L, result);
                return 1;
            }
            case MM_OBJCType_short: {
                short result = 0;
                [invocation getReturnValue: &result];
                lua_pushnumber(L, result);
                return 1;
            }
            case MM_OBJCType_ushort: {
                unsigned short result = 0;
                [invocation getReturnValue: &result];
                lua_pushnumber(L, result);
                return 1;
            }
            case MM_OBJCType_int: {
                int result = 0;
                [invocation getReturnValue: &result];
                lua_pushnumber(L, result);
                return 1;
            }
            case MM_OBJCType_uint: {
                unsigned int result = 0;
                [invocation getReturnValue: &result];
                lua_pushnumber(L, result);
                return 1;
            }
            case MM_OBJCType_long: {
                long result = 0;
                [invocation getReturnValue: &result];
                lua_pushnumber(L, result);
                return 1;
            }
            case MM_OBJCType_ulong: {
                unsigned long result = 0;
                [invocation getReturnValue: &result];
                lua_pushnumber(L, result);
                return 1;
            }
            case MM_OBJCType_llong: {
                long long result = 0;
                [invocation getReturnValue: &result];
                lua_pushnumber(L, result);
                return 1;
            }
            case MM_OBJCType_ullong: {
                unsigned long long result = 0;
                [invocation getReturnValue: &result];
                lua_pushnumber(L, result);
                return 1;
            }
            case MM_OBJCType_float: {
                float result = 0;
                [invocation getReturnValue: &result];
                lua_pushnumber(L, result);
                return 1;
            }
            case MM_OBJCType_double: {
                double result = 0;
                [invocation getReturnValue: &result];
                lua_pushnumber(L, result);
                return 1;
            }
            case MM_OBJCType_char_ptr: {
                char *result = 0;
                [invocation getReturnValue: &result];
                lua_pushlightuserdata(L, result);
                return 1;
            }
            case MM_OBJCType_void_ptr: {
                void *result = 0;
                [invocation getReturnValue: &result];
                lua_pushlightuserdata(L, result);
                return 1;
            }
            case MM_OBJCType_rect:{
                CGRect rect = CGRectZero;
                [invocation getReturnValue:&rect];
                mm_lua_pushcgrect(L, rect);
                return 1;
            }
            case MM_OBJCType_size:{
                CGSize size = CGSizeZero;
                [invocation getReturnValue:&size];
                mm_lua_pushcgsize(L, size);
                return 1;
            }
            case MM_OBJCType_point:{
                CGPoint point = CGPointZero;
                [invocation getReturnValue:&point];
                mm_lua_pushcgpoint(L, point);
                return 1;
            }
            default: {
                NSInteger value = 0;
                NSCAssert(value, @"Undefined parameter type!");
                [invocation setArgument: &value atIndex:index];
                LVError(@"Undefined parameter type!");
                return 0; // 参数类型不支持
            }
        }
    }
    NSCAssert(NO, @"An error occurred about the parameter type!");
    return 0;
}

上面对应每一种返回的参数类型 做了switch。在invocation中获取相应的参数。然后压入lua栈中。普通数据类型,转成Lua可以接收的类型压栈,Lua不能直接接收的id类型。并没有继续采用SDK内部的包装一个LVBox的方式。而是进行了自己的创新,把每一种具体的类型都展开。当然userdata的话转为相应的userdata并压栈。具体代码如下。

void mm_lua_pushnativeobj (lua_State* L, id value) {
    lua_checkstack(L, 4);
    
    if( [value isKindOfClass:[NSString class]] ) {
        NSString* s = value;
        lua_pushstring(L, s.UTF8String);
    } else if( [value isKindOfClass:[NSDictionary class]] ) {
        NSDictionary* dictionary = value;
        lua_newtable(L);
        for (NSString *key in dictionary) {
            NSString* value = dictionary[key];
            lua_checkstack(L, 4);
            lua_pushstring(L, key.UTF8String);
            mm_lua_pushnativeobj(L,value);
            lua_settable(L, -3);
        }
    } else if( [value isKindOfClass:[NSArray class]] ) {
        NSArray* array = value;
        lua_newtable(L);
        for (int i=0; i<array.count; i++) {
            id value = array[i];
            lua_pushnumber(L, i+1);
            mm_lua_pushnativeobj(L,value);
            lua_settable(L, -3);
        }
    } else if( [value isKindOfClass:[NSNumber class]] ) {
        static Class boolClass = nil;;
        if ( boolClass == nil ) {
            boolClass = [@(YES) class];
        }
        NSNumber* number = value;
        if( [value class] == boolClass) {
            //  是否是bool类型
            lua_pushboolean(L, number.boolValue);
        } else {
            lua_pushnumber(L, number.doubleValue);
        }
    }  else if( value == nil || value == [NSNull null] ) {
        lua_pushnil(L);
    }  else if( value && [value isKindOfClass:[UIImage class]] ) {
        // 直接使用LVBitmap。生成Bitmap包装成userdata压栈
        mm_lua_pushnativeimage(L, value);
    }  else if( value && [value isKindOfClass:[NSData class]] ) {
        // 直接使用LVData 关联真实的data
        mm_lua_pushnativedata(L, value);
    }  else if( value && [value isKindOfClass:[NSDate class]] ) {
        // 直接使用LVDate。关联真实的日期。然后将生成的userdata压栈
        mm_lua_pushnativedate(L, value);
    } else if ([value conformsToProtocol:@protocol(MILEntityClassProtocol)]){
        NSCAssert([[value class] respondsToSelector:@selector(pluginOfLua)], @"The @sel(pluginOfLua) must be responds!");
        // 最经典的~ 。 满足相应协议的,直接通过协议拿到相应的插件,插件通过setUp根据宿主类的相关信息生成userdata 然后压栈。
        mm_lua_pushEntity(L, (id<MILEntityClassProtocol>)value);
    } else {
        NSCAssert(NO, @"An error occurred about the parameter type!");
    }
}

返回值为Lua端在栈中获取相应参数的个数

    原文作者:沧州宁少
    原文地址: https://www.jianshu.com/p/54f562305582
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞