Cocos 2dx项目lua调用OC出现卡死但不闪退的坑

Posted jxst441192

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Cocos 2dx项目lua调用OC出现卡死但不闪退的坑相关的知识,希望对你有一定的参考价值。

    最近新上线的一个游戏,发现线上游戏有部分功能在点击的时候出现了没有反应的情况。通过调试源码,发现是原生OC的代码出现了崩溃,但是比较奇怪的是线上的Bugly没有任何记录,这个功能属于高频高能,而且又是非常重要的功能,所以我下定决心查个明白。后来通过查看cocos2d_lua_bindings的源码,发现是cocos2d_lua_bindings中的CCLuaObjcBridge.mm166行把这个崩溃给catch了。。所以质检部门也没发现这个错误,可能是以为游戏只是卡了下,真的是坑死人不偿命啊。

    下面是CCLuaObjcBridge.mm的源码

/**
 className
 methodName
 args
 */
int LuaObjcBridge::callObjcStaticMethod(lua_State *L)
{
    if (lua_gettop(L) != 3 || !lua_isstring(L, -3) || !lua_isstring(L, -2))
    {
        lua_pushboolean(L, 0);
        lua_pushinteger(L, kLuaBridgeErrorInvalidParameters);
        return 2;
    }
    
    const char *className  = lua_tostring(L, -3);
    const char *methodName = lua_tostring(L, -2);
    if (!className || !methodName)
    {
        lua_pushboolean(L, 0);
        lua_pushinteger(L, kLuaBridgeErrorInvalidParameters);
        return 2;
    }
    
    Class targetClass = NSClassFromString([NSString stringWithCString:className encoding:NSUTF8StringEncoding]);
    if (!targetClass)
    {
        lua_pushboolean(L, 0);
        lua_pushinteger(L, kLuaBridgeErrorClassNotFound);
        return 2;
    }
    
    SEL methodSel;
    bool hasArguments = lua_istable(L, -1);
    if (hasArguments)
    {
        NSString *methodName_ = [NSString stringWithCString:methodName encoding:NSUTF8StringEncoding];
        methodName_ = [NSString stringWithFormat:@"%@:", methodName_];
        methodSel = NSSelectorFromString(methodName_);
    }
    else
    {
        methodSel = NSSelectorFromString([NSString stringWithCString:methodName encoding:NSUTF8StringEncoding]);
    }
    if (methodSel == (SEL)0)
    {
        lua_pushboolean(L, 0);
        lua_pushinteger(L, kLuaBridgeErrorMethodNotFound);
        return 2;
    }
    
    NSMethodSignature *methodSig = [targetClass methodSignatureForSelector:(SEL)methodSel];
    if (methodSig == nil)
    {
        lua_pushboolean(L, 0);
        lua_pushinteger(L, kLuaBridgeErrorMethodSignature);
        return 2;
    }
    
    @try {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setTarget:targetClass];
        [invocation setSelector:methodSel];
        NSUInteger returnLength = [methodSig methodReturnLength];
        const char *returnType = [methodSig methodReturnType];
        
        if (hasArguments)
        {
            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            lua_pushnil(L);
            while (lua_next(L, -2))
            {
                NSString *key = [NSString stringWithCString:lua_tostring(L, -2) encoding:NSUTF8StringEncoding];
                
                switch (lua_type(L, -1))
                {
                    case LUA_TNUMBER:
                        [dict setObject:[NSNumber numberWithFloat:lua_tonumber(L, -1)] forKey:key];
                        break;
                        
                    case LUA_TBOOLEAN:
                        [dict setObject:[NSNumber numberWithBool:lua_toboolean(L, -1)] forKey:key];
                        break;
                        
                    case LUA_TSTRING:
                        [dict setObject:[NSString stringWithCString:lua_tostring(L, -1) encoding:NSUTF8StringEncoding]
                                 forKey:key];
                        break;
                        
                    case LUA_TFUNCTION:
                        int functionId = retainLuaFunction(L, -1, NULL);
                        [dict setObject:[NSNumber numberWithInt:functionId] forKey:key];
                        break;
                }
                
                lua_pop(L, 1);
            }
            
            [invocation setArgument:&dict atIndex:2];
            [invocation invoke];
        }
        else
        {
            [invocation invoke];
        }
        
        lua_pushboolean(L, 1);
        if (returnLength > 0)
        {
            if (strcmp(returnType, "@") == 0)
            {
                id ret;
                [invocation getReturnValue:&ret];
                pushValue(L, ret);
            }
            else if (strcmp(returnType, "c") == 0) // BOOL
            {
                char ret;
                [invocation getReturnValue:&ret];
                lua_pushboolean(L, ret);
            }
            else if (strcmp(returnType, "i") == 0) // int
            {
                int ret;
                [invocation getReturnValue:&ret];
                lua_pushinteger(L, ret);
            }
            else if (strcmp(returnType, "f") == 0) // float
            {
                float ret;
                [invocation getReturnValue:&ret];
                lua_pushnumber(L, ret);
            }
            else
            {
                NSLog(@"not support return type = %s", returnType);
                lua_pushnil(L);
            }
        }
        else
        {
            lua_pushnil(L);
        }
        return 2;
    }
    @catch (NSException *exception) //就是这处代码导致崩溃被catch了,正确的做法应该是测试阶段直接throw exception,上线后通过bugly手动上报这个exception对象
{ NSLog(@"EXCEPTION THROW: %@", exception); lua_pushboolean(L, 0); lua_pushinteger(L, kLuaBridgeErrorExceptionOccurred); return 2; } }

以上是关于Cocos 2dx项目lua调用OC出现卡死但不闪退的坑的主要内容,如果未能解决你的问题,请参考以下文章

cocos2dx-lua 3.10 中怎样移除layer

带有 LUA 的 Cocos2dx iOS 项目

Mac开发cocos2dx-lua用啥工具?

Cocos2dx的http请求流程,lua版

cocos2dx-lua 能不能用AMF3来加密lua源文件

quick cocos Lua与OC互相回调,苹果内购机制