根据用户数据在Objective C/C中创建Lua全局变量 [英] Creating Lua globals in Objective C/C from userdata

查看:90
本文介绍了根据用户数据在Objective C/C中创建Lua全局变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个库,以允许对iOS 5.x中的游戏进行Lua(5.2)脚本编写.我创建了一个类并添加了绑定,以使其可以从Lua创建和访问.从Lua调用的C初始化方法如下:

I am working on a library to allow Lua (5.2) scripting of games in iOS 5.x. I have created a class and added bindings to allow it to be created and accessed form Lua. The C initializer method called from Lua is given below:

static int newGeminiObject(lua_State *L){
    GeminiObject *go = [[GeminiObject alloc] initWithLuaState:L];

    GeminiObject **lgo = (GeminiObject **)lua_newuserdata(L, sizeof(GeminiObject *));
    *lgo = go;

    luaL_getmetatable(L, GEMINI_OBJECT_LUA_KEY);
    lua_setmetatable(L, -2);

    lua_newtable(L);
    lua_setuservalue(L, -2);

    NSLog(@"New GeminiObject created");

    // add this new object to the globall list of objects
    [[Gemini shared].geminiObjects addObject:go];

    return 1;

}

这会分配一个在其他地方设置的元表,以提供对各种方法的访问.此外,它还附加了一个表作为用户值,以允许脚本代码将属性分配给对象.

This assigns a metatable which is set up elsewhere to provide access to various methods. Additionally, it attaches a table as a uservalue to allow script code to assign attributes to the objects.

我可以毫无问题地在Lua脚本中创建这些对象:

I can create these objects in Lua scripts with no problem:

require "gemini"
x = gemini.new()
x:addEventListener("touch", objectTouched)

在这里objectTouched是在其他地方定义的处理触摸事件的Lua方法.在这里,addEventListener将其绑定到touch事件.

Here objectTouched is a a Lua method defined elsewhere that handles a touch event. Here addEventListener binds it to touch events.

这些对象可以正常工作.但是,当我尝试从C创建一个时,我遇到了问题.我可以创建对象,但是尝试将其分配给全局对象然后在脚本中调用它会失败.

These objects work just fine. When I attempt to create one from C, however, I am running into problems. I can create the object, but trying to assign it to a global and then invoke it in a script fails.

下面的C代码运行

-(void) addRuntimeObject {
    GeminiObject *rt = [[GeminiObject alloc] initWithLuaState:L];
    GeminiObject **lruntime = (GeminiObject **)lua_newuserdata(L, sizeof(GeminiObject *));
    *lruntime = rt;

    // set the metatable - effectively declaring the type for this object
    luaL_getmetatable(L, GEMINI_OBJECT_LUA_KEY);
    lua_setmetatable(L, -2);

    // add a table to hold anything the user wants to add
    lua_newtable(L);
    lua_setuservalue(L, -2);

    // create an entry in the global table
    lua_setglobal(L, "Runtime");

    // empty the stack
    lua_pop(L, lua_gettop(L));
}

这应该定义一个名为"Runtime"的全局变量.尝试从这样的脚本中访问此变量

This should define a global named "Runtime". Trying to access this variable from a script like this

Runtime:addEventListener("enterFrame", enterFrame)

导致以下错误:

attempt to index global 'Runtime' (a userdata value)

这是一个userdata值,但是当我直接在Lua中创建一个值时,这似乎无关紧要.元表绑定提供对方法和元方法的访问.同样,如果该对象是从Lua创建的,那么效果很好,但不是在C语言中创建时.

It is a userdata value, but this doesn't seem to matter when I create one in Lua directly. The metatable binding provides access to the methods and metamethods. Again, this works fine if the object is created from Lua, just not when it is created in C.

关于我在这里做错什么的任何想法,或者从userdata进行全局创建的正确方法是什么?

Any ideas as to what I'm doing wrong here, or what the correct way to make a global from userdata is?

编辑

基于以下有关GEMINI_OBJECT_LUA_KEY的混淆的评论,我想我会列出绑定中实际使用的代码:

Based on comments below regarding confusion about GEMINI_OBJECT_LUA_KEY, I thought I would list the code that is actually used in the binding:

static const struct luaL_Reg geminiObjectLib_f [] = {
    {"new", newGeminiObject},
    {NULL, NULL}
};

static const struct luaL_Reg geminiObjectLib_m [] = {
    {"addEventListener", addEventListener},
    {"__gc", geminiObjectGC},
    {"__index", l_irc_index},
    {"__newindex", l_irc_newindex},
    {NULL, NULL}
};

int luaopen_geminiObjectLib (lua_State *L){
    // create the metatable and put it into the registry
    luaL_newmetatable(L, GEMINI_OBJECT_LUA_KEY);

    lua_pushvalue(L, -1); // duplicates the metatable


    luaL_setfuncs(L, geminiObjectLib_m, 0);

    // create a table/library to hold the functions
    luaL_newlib(L, geminiObjectLib_f);

    NSLog(@"gemini lib opened");

    return 1;
}

此代码注册了提供GeminiObjects方法和元方法的函数库(此处未显示).对luaL_newmetatable的调用将创建一个新的元表,并将其在注册表中与键GEMINI_OBJECT_LUA_KEY关联. GEMINI_OBJECT_LUA_KEY只是在标头中定义的唯一字符串. luaL_setfuncs实际上将函数指针添加到了元表中,使它们可用作对象的方法.

This code registers the library of functions (not show here) that provide the methods and metamethods for the GeminiObjects. The call to luaL_newmetatable creates a new metatable and associates it in the registry with the key GEMINI_OBJECT_LUA_KEY. GEMINI_OBJECT_LUA_KEY is just a unique string defined in the header. luaL_setfuncs actually adds the function pointers to the metatable, making them available as methods of the objects.

推荐答案

如果仍然有人感兴趣,我会从Lua邮件列表上的亲切朋友那里得到我问题的答案.这里的问题是在我调用addRuntimeObject之前没有调用库绑定函数luaopen_geminiObjectLib.

In case anyone is still interested, I got the answer to my question from the kind folks on the Lua mailing list. The problem here is that the library binding function luaopen_geminiObjectLib is not called before my call to addRuntimeObject.

由于iOS不支持动态库,因此我通过向Lua源代码的linit.c中的preloadedlibs数组添加指向它们的指针来静态添加了我的库.不幸的是,在Lua脚本中执行require('libname')之前,不会加载以这种方式添加的库.由于我在执行Lua脚本之前调用了addRuntimeObject方法,因此该库尚未加载.

Since iOS does not support dynamic libraries, I had added my libraries in statically by adding pointers to them to the preloadedlibs array in linit.c of the Lua source. Unfortunately, libraries added this way are not loaded until require('libname') is executed in a Lua script. Since I was calling my addRuntimeObject method prior to executing the Lua script, the library was not yet loaded.

解决方案是将指向luaopen_geminiObjectLib的指针添加到同一linit.c文件中的loadedlibs数组.这会导致在Lua启动时加载库,而无需脚本require.

The solution is to add the pointer to luaopen_geminiObjectLib to the loadedlibs array in the same linit.c file. This causes the library to be loaded when Lua starts up with no need for scripts to require it.

这篇关于根据用户数据在Objective C/C中创建Lua全局变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆