ios lua 交互

lua文件結(jié)構(gòu)

名稱 ? ? ? ? ?說明

docLua ? ?相關(guān)的文檔,包括了編譯文檔、接口文檔等

Makefile ? 編譯Lua使用,在這里我們不使用它來進(jìn)行編譯

README ? 關(guān)于Lua的說明文件

src ? ? ? ? ? ? ?Lua的源碼文件

注意:在這里我們只需要src目錄中的源碼文件,先打開src目錄,將Makefile、lua.c、luac.c三個(gè)文件刪除掉,需要說明的是lua.c和luac.c文件是用于編譯生成lua和luac兩個(gè)命令不屬于解析器的功能,如果不刪除可能會(huì)導(dǎo)致XCode無法編譯通過。


ios system函數(shù)不可用:

1.導(dǎo)入頭文件:#include<ftw.h>

2.聲明unlink_cb方法:

int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)

{

? ? int rv = remove(fpath);

? ? if (rv)

? ? ? ? perror(fpath);

?? ?????return rv;

}

3.使用nftw:

nftw(luaL_optstring(L, 1, NULL), unlink_cb, 64, FTW_DEPTH|FTW_PHYS)

lua架構(gòu)圖

1.c api

在開始實(shí)現(xiàn)Lua與OC交互之前先來了解兩個(gè)非常重要的概念,一個(gè)是Lua的C Api,Lua解釋器是使用C語言來編寫的,因此它提供了豐富的C語言定義的接口來訪問和操作Lua中的所有元素;

另外一個(gè)就是?的概念,在Lua和C進(jìn)行交互數(shù)據(jù)的時(shí)候會(huì)用到了一個(gè)棧的結(jié)構(gòu),棧中的每個(gè)元素都能保存任何類型的Lua值。要獲取Lua中的一個(gè)值時(shí),需要調(diào)用一個(gè)C Api函數(shù),Lua就會(huì)將特定的值壓入棧中,然后再通過相應(yīng)的C Api將值取出來


通過c api獲取lua的值的過程

同樣,要將一個(gè)值傳給Lua時(shí),需要先調(diào)用C Api將這個(gè)值壓入棧,然后再調(diào)用C Api,Lua就會(huì)獲取該值并將其從棧中彈出。 如圖所示:

通過c api 傳遞給lua值的的過程

關(guān)于棧中位置在lua中有兩種形式表示,第一種是正數(shù)表示法,1表示棧底元素(即最先入棧的元素),然后越往上的元素,索引值越大。另外一種是負(fù)數(shù)表示法,-1表示棧頂元素(即最后入棧的元素),然后越往下的元素,索引值越小。如圖所示:


stack

1.關(guān)于棧操作的C Api

C Api中提供了很多操作棧的功能接口,通??梢苑譃樗拇箢悾喝霔2僮?、查詢操作、取值操作和其他操作。

1.1 入棧操作

表示要將本地的某個(gè)類型的值放到數(shù)據(jù)棧中,然后提供給Lua層來獲取和操作。

void lua_pushnil (lua_State *L);

void lua_pushnumber (lua_State *L, lua_Number n);

void lua_pushinteger (lua_State *L, lua_Integer n);

const char *lua_pushlstring (lua_State *L, const char *s, size_t len)?;

const char *lua_pushstring (lua_State *L, const char *s);

const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);

const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

void lua_pushboolean (lua_State *L, int b);

void lua_pushlightuserdata (lua_State *L, void *p);

int lua_pushthread (lua_State *L);

從上面的接口方法定義可以看出來,不同的Lua類型對(duì)應(yīng)著不通的入棧接口,包括了整型(Integer)、布爾類型(Boolean)、浮點(diǎn)數(shù)(Number)、字符串(String)、閉包(Closure)、用戶自定義數(shù)據(jù)(Userdata)、空類型(Nil)以及線程(Thread)。需要注意的是,C Api沒有提供直接入棧Table類型的接口(估計(jì)是該數(shù)據(jù)類型無法與本地結(jié)構(gòu)進(jìn)行對(duì)應(yīng)),如果需要入棧一個(gè)Table類型,可以使用lua_createtable方法來入棧一個(gè)Table,調(diào)用該方法會(huì)在棧頂放入一個(gè)Table的引用。

例子:lua_pushinteger (state, 1); ?//把1這個(gè)值放到棧頂

lua_setglobal (state, "a"); ?//把棧頂?shù)脑胤湃朐摲椒ǖ诙€(gè)參數(shù)所指定的變量名對(duì)應(yīng)的lua變量中,同時(shí)移除棧頂元素。如圖:

lua_setglobal操作

?1.2查詢操作

之前說到棧中的每個(gè)元素都可以為任意類型,那么,對(duì)于如何判斷元素的類型就可以通過該類方法來實(shí)現(xiàn)。該類方法的定義如下:

int lua_isnil (lua_State *state, int index);

int lua_isboolean (lua_State *state, int index);

int lua_isfunction (lua_State *state, int index);

int lua_istable (lua_State *state, int index);

int lua_islightuserdata (lua_State *state, int index);

int lua_isthread (lua_State *state, int index);

int lua_isnumber (lua_State *L, int idx);

int lua_isinteger (lua_State *L, int idx);

int lua_iscfunction (lua_State *L, int idx);

int lua_isstring (lua_State *L, int idx);

int lua_isuserdata (lua_State *L, int idx)

注意第二個(gè)參數(shù)index,可以有兩種形式;第一種是n位于棧頂,第二種是-1位于棧頂;如下圖:

棧index

lua_isXXX系列方主要是判斷棧中數(shù)據(jù)是否能夠被轉(zhuǎn)換為對(duì)應(yīng)數(shù)據(jù)類型時(shí)使用,如lua_isstring方法則是判斷棧中某個(gè)元素是否能夠被轉(zhuǎn)換為string類型,所以當(dāng)棧中數(shù)據(jù)為number類型時(shí),其返回值也為true。

如果要進(jìn)行非轉(zhuǎn)換的強(qiáng)類型判斷,可以使用lua_type方法來獲取棧中元素的類型,然后根據(jù)類型來獲取值。如判斷棧頂元素的類型:

switch(lua_type(state, -1)){

? ? case LUA_TNUMBER:

? ? ? ? break;

? ? case LUA_TSTRING:

? ? ? ? break;

? ? ?。。。。。。。

? ? ? default:

? ? ? ? break;

}

1.3 取值操作

當(dāng)知道某個(gè)數(shù)據(jù)類型后,則調(diào)用對(duì)應(yīng)數(shù)據(jù)類型的取值方法來獲取元素。其方法定義如下:

int lua_toboolean (lua_State *L, int idx);

const char *lua_tolstring (lua_State *L, int idx, size_t *len);

lua_CFunction lua_tocfunction (lua_State *L, int idx);

void *lua_touserdata (lua_State *L, int idx);

lua_State *lua_tothread (lua_State *L, int idx);

const void *lua_topointer (lua_State *L, int idx);

lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum);

lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum);

要注意的是該系列接口跟lua_isXXX系列接口一樣,會(huì)對(duì)原始的類型進(jìn)行轉(zhuǎn)換輸出,因此在做一些跟類型相關(guān)的操作時(shí),最好時(shí)先判斷類型再根據(jù)類型調(diào)用該方法取值

1.4 其他操作

int lua_gettop (lua_State *L);

void lua_settop (lua_State *L, int idx);

void lua_pushvalue (lua_State *L, int idx);

void lua_remove(lua_State *L, int idx);

void lua_insert(lua_State *L, int idx);

void lua_replace(lua_State *L, int idx);

void lua_pop(lua_State *L, int n);

lua_gettop:獲取棧頂位置,也即是棧中元素的個(gè)數(shù),其實(shí)這個(gè)方法在處理原生方法的傳入?yún)?shù)時(shí)很有用,可以確認(rèn)傳入?yún)?shù)的個(gè)數(shù)。有時(shí)候也可以用它來輸出各個(gè)狀態(tài)下的棧元素變化,來確認(rèn)自己在操作棧時(shí)是否存在問題。

lua_settop:用于設(shè)置棧頂位置,如果新棧頂高于之前的棧頂則會(huì)push一些nil的元素來填充;如果新棧頂?shù)陀谥暗臈m攧t會(huì)丟棄新棧頂之上的所有元素。如圖所示:


lua_settop

lua_pushvalue:表示將棧中某個(gè)元素的副本壓入棧頂。之前的棧元素不會(huì)發(fā)生變動(dòng)。如圖所示:


lua_pushvalue

lua_remove方法用于移除指定索引上的元素,然后再該元素之上的所有元素會(huì)下移填補(bǔ)空缺(即元素的索引會(huì)發(fā)生變更)。如圖所示:


lua_remove

lua_insert會(huì)將指定索引位置之上的所有元素上移來開辟一個(gè)新的位置。然后將棧頂元素插入到該位置。如圖所示:


lua_insert

lua_replace方法會(huì)先彈出棧頂元素,然后將該元素覆蓋到指定索引位置上(棧就減少了少了一個(gè)元素)。如圖所示:

lua_replace

lua_pop方法會(huì)從棧頂彈出指定數(shù)量的元素。如圖所示:

lua_pop

2.?From OC to Lua

2.1 空值傳遞

使用lua_pushnil方法可以將任意一個(gè)Lua變量置空。如:

lua_pushnil(); ?//推到棧上

lua_setglobal(self.state, "val"); //棧上到c空間

2.2 數(shù)值的傳遞

使用lua_pushinteger或者lua_pushnumber方法來將OC中的數(shù)值類型傳遞到Lua中指定的某個(gè)變量。如:

//傳遞整型值

lua_pushinteger(self.state, 1024);

lua_setglobal(self.state, "intVal");

//傳遞浮點(diǎn)型

lua_pushnumber(self.state, 80.08);

lua_setglobal(self.state, "numVal");

2.3 布爾值的傳遞

使用lua_pushboolean方法來實(shí)現(xiàn),如:

lua_pushboolean(self.state, YES);

lua_setglobal(self.state, "boolVal");

2.4 字符串的傳遞

使用lua_pushstring方法可以傳遞字符串給Lua,要注意的是該方法接收的是一個(gè)c描述的字符串(即 char*)。如:

lua_pushstring(self.state, @"Hello World".UTF8String);

lua_setglobal(self.state, "stringVal");

2.5 二進(jìn)制數(shù)組的傳遞

二進(jìn)制數(shù)組在Lua中其實(shí)與字符串的存儲(chǔ)方式相同,但是OC中不能直接使用lua_pushstring來進(jìn)行二進(jìn)制數(shù)組的傳遞,可以使用lua_pushlstring方法來傳遞。如:

char bytes[13] = {0xf1, 0xaa, 0x12, 0x56, 0x00, 0xb2, 0x43, '\0', '\0', 0x00, 0x90, 0x65, 0x73};

lua_pushlstring(self.state, bytes, 13);

lua_setglobal(self.state, "bytesVal");

2.6 方法的傳遞

Lua中只能接受C定義的方法傳入,并且方法的聲明必須符合lua_CFunction函數(shù)指針的定義,即:

int printHelloWorld (lua_State *state){

? ? NSLog(@"Hello World!");

? ? return 0;

}

lua_pushcfunction(self.state, printHelloWorld);

lua_setglobal(self.state, "funcVal");

操作完成后,在Lua中就可以直接調(diào)用了:

funcVal();

如果oc的方法是允許接受參數(shù)的,那么可以從state參數(shù)里面獲取傳入的參數(shù)。拿上面的例子,例如方法接收一個(gè)名字的字符串參數(shù),函數(shù)的代碼則可以修改為:

int printHelloWorld (lua_State*state){

? ? if(lua_gettop(state)>0){

? ? ? ? const char*name =lua_tostring(state,1); //取值操作會(huì)刪除棧頂元素

? ? ? ? const char*name2 =lua_tostring(state,2);

? ? ? ? NSLog(@"Hello--%s--%s",name,name2); //

? ? }

? ? return 0;

}

lua中調(diào)用:funcVal("aaa","bbb")

輸出:Hello--aaa--bbb

如果定義的方法不是直接打印字符串,而是組合了字符串給Lua返回,那么定義的方法里面則需要配合’lua_pushXXXX’系列方法來進(jìn)行返回值傳遞。需要注意的是:方法中return的數(shù)量要與push到棧中的值要一致,否則可能出現(xiàn)異常。那么,上面定義的函數(shù)可以做如下修改:

int printHelloWorld (lua_State*state){

? ? if(lua_gettop(state)>0){

? ? ? ? constchar*name =lua_tostring(state,1);

? ? ? ? NSString*retVal = [NSStringstringWithFormat:@"Hollo %s",name];

? ? ? ? lua_pushstring(state, retVal.UTF8String);

? ? ? ? return 1; //直接返回,因?yàn)橹挥幸粋€(gè)return,那么也只能push一次

? ? }

? ? return 0;

}

然后在Lua中則可以這樣調(diào)用:

local retVal = funcVal("vimfung");

print(retVal);

輸出:Hollo vimfung

2.7 數(shù)組和字典的傳遞

在Lua中,數(shù)組(Array)和字典(Dictionary)都由一個(gè)Table類型所表示(在Lua看來數(shù)組其實(shí)也屬于一種字典,只是它的key是有序并且為整數(shù))。如:

-- 定義數(shù)組 local arrayVal = {1,2,3,4,5,6};

-- 定義字典 local dictVal = {a=1, b=3, c=4, d=5};

上面的例子分別用了不帶key的聲明和帶key的聲明兩種方式來創(chuàng)建Table類型。其中不帶key的聲明方式,解析器會(huì)默認(rèn)為其創(chuàng)建一個(gè)key,該key是從1開始,由小到大進(jìn)行分配,其等效于:

local arrayVal = {1=1, 2=2, 3=3, 4=4, 5=5, 6=6};

當(dāng)然,兩種方式是可以混合使用,如:

local tbl = {1, 2, a=1, b=2, 3};

Table屬于比較復(fù)雜的數(shù)據(jù)結(jié)構(gòu),因此提供操作它的C Api也比較復(fù)雜,下面將根據(jù)數(shù)組和字典分別講述它們的傳遞方式。

2.7.1 數(shù)組傳遞

首先,需要將一個(gè)Table類型入棧,這樣才能對(duì)其進(jìn)行進(jìn)一步的操作。由于沒有pushtable這樣的方法,但是可以使用lua_newtable來創(chuàng)建一個(gè)Table對(duì)象,并且該對(duì)象會(huì)自動(dòng)放入棧頂位置。如:

lua_newtable(self.state); //創(chuàng)建一個(gè)Table對(duì)象并放入棧頂

然后對(duì)要傳遞的數(shù)組進(jìn)行遍歷,并通過lua_rawseti方法將元素值設(shè)置到Table中。如:

NSArray *array = @[@1, @2, @3, @4, @5, @6];

?[array enumerateObjectsUsingBlock:^(id? _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? NSInteger value = [obj integerValue];

? ? lua_pushinteger(self.state, value);?

? ? lua_rawseti(self.state, -2, idx + 1); //將當(dāng)前棧頂元素放入Table中,第二個(gè)參數(shù)代表Table在棧中的位置,第三個(gè)參數(shù)代表放入Table的位置

}];

lua_setglobal(self.state, "arrayVal");?


lua_rawseti


2.7.2 字典傳遞

字典的傳遞同樣需要先入棧一個(gè)Table:

lua_newtable(self.state);

然后對(duì)要傳遞的字典進(jìn)行遍歷,并通過lua_setfield方法將元素設(shè)置到Table中。如:

[dict enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, id? _Nonnull obj, BOOL * _Nonnull stop) {

? ? NSInteger value = [obj integerValue];

? ? lua_pushinteger(self.state, value);

? ? lua_setfield(self.state, -2, key.UTF8String);

}];

lua_setglobal(self.state, "dictVal");

lua_setfield與lua_rawseti功能類型,都是把一個(gè)元素放入Table中,只是一個(gè)用于指定整數(shù)索引,一個(gè)是指定字符串索引。通過上面的方式就可以把字典傳遞給Lua了。

2.8 自定義數(shù)據(jù)傳遞

Lua中一個(gè)比較強(qiáng)大的地方是它可以將任意的類型(包括類對(duì)象)進(jìn)行傳遞。特別是在提供原生處理方法時(shí),需要用到一些特定的數(shù)據(jù)類型作為參數(shù)時(shí),Lua就可以幫我們實(shí)現(xiàn)這一塊的傳遞。

要想傳遞自定義的數(shù)據(jù)則必須要使用Lua提供的Userdata類型。該類型有兩種引用方式,一種是強(qiáng)引用Userdata,由Lua的GC來負(fù)責(zé)該類型變量的生命周期。另外一種是弱引用Userdata,又稱Light Userdata,該類型不被GC所管理,其生命周期由原生層來決定。下面來看一下兩種方式是如何實(shí)現(xiàn)的。

首先我們來定義一個(gè)OC的User類:

@interface User : NSObject

@property (nonatomic, copy) NSString *name;

@end

利用lua_newuserdata方法來創(chuàng)建一個(gè)強(qiáng)引用Userdata,并創(chuàng)建一個(gè)User對(duì)象賦值給新建的Userdata。如:

void *instanceRef = lua_newuserdata(self.state, sizeof(User *));

instanceRef = (__bridge_retained void *)[[User alloc] init];

lua_setglobal(self.state, "userdataVal");

通過上面的代碼就可以把User類實(shí)例封裝成Userdata再傳遞給Lua。如果你要傳遞的對(duì)象并不需要Lua來管理生命周期,那么就可以創(chuàng)建一個(gè)弱引用的Userdata,如:

User *user = [[User alloc] init];

lua_pushlightuserdata(self.state, (__bridge void *)(user));

lua_setglobal(self.state, "userdataVal");

例子

1.//定義c函數(shù)

static int printUser (lua_State *state){

? ? if (lua_gettop(state) > 0)?{

? ? ? ? //表示有參數(shù)傳入

? ? ? ? User *user = (__bridge User *)(lua_topointer(state, 1));

? ? ? ? NSLog(@"user.name = %@", user.name);

? ? }

? ? return 0;

}

2.該方法通過lua_topointer方法來獲取了一個(gè)Userdata數(shù)據(jù)類型并轉(zhuǎn)換為User類實(shí)例對(duì)象然后打印其名稱。接下來將其導(dǎo)出給Lua:

lua_pushcfunction(self.state, printUser);

lua_setglobal(self.state, "printUser");?//把printUser函數(shù)暴露給lua

3.然后生成一個(gè)User對(duì)象,并調(diào)用該方法傳入該用戶對(duì)象。如:

//創(chuàng)建User對(duì)象

User *user = [[User alloc] init];

user.name = @"vimfung";

lua_getglobal(self.state, "printUser"); //把lua中的printUser函數(shù)放入棧中

//傳入U(xiǎn)ser參數(shù)

lua_pushlightuserdata(self.state, (__bridge void *)(user)); //把user對(duì)象放入棧中

lua_pcall(self.state, 1, 0, 0); //表示調(diào)用棧中的函數(shù),第二個(gè)參數(shù)為函數(shù)參數(shù)的數(shù)量,第三個(gè)是返回值的數(shù)量,第四個(gè)參數(shù)是用于發(fā)生錯(cuò)誤處理時(shí)的代碼返回

最終的輸出信息如下:user.name = vimfung

3.From Lua to OC

3.1 獲取數(shù)值

lua_getglobal(self.state, "aa"); //從c空間到棧上

double value = lua_tonumber(self.state, -1); //從棧到oc空間

NSLog(@"aa = %f", value);

lua_pop(self.state, 1);

lua_getglobal方法是用于獲取全局變量的值,調(diào)用它會(huì)把一個(gè)值放入棧頂。然后再通過lua_tonumber把棧頂?shù)闹底x取出來并打印。需要注意的是通過lua_getglobal獲取得到的值,在棧中是不會(huì)自動(dòng)清除,因此,在用完某個(gè)變量時(shí)記得把它從棧中清除掉,代碼中是通過lua_pop把值彈出棧的。

3.2 獲取布爾值

與獲取數(shù)值相同,通過lua_toboolean方法來獲取某個(gè)布爾變量的值。如:

lua_getglobal(self.state, "aa");

BOOL value = lua_toboolean(self.state, -1);

if (value){

? NSLog(@"aa = YES");

}

else{

? NSLog(@"aa = NO");

}

lua_pop(self.state, 1);

3.3 獲取字符串

lua_tostring方法來獲取字符串變量的值。如:

lua_getglobal(self.state, "aa");

const char *value = lua_tostring(self.state, -1);

NSLog(@"aa = %s", value);

lua_pop(self.state, 1);

3.4 獲取二進(jìn)制數(shù)組

lua_tolstring方法來獲二進(jìn)制數(shù)組變量的值。如:

lua_getglobal(self.state, "aa");

size_t len = 0;

const char *bytes = lua_tolstring(self.state, -1, &len);

NSData *data = [NSData dataWithBytes:bytes length:len];

NSLog(@"aa = %@", data);

lua_pop(self.state, 1);

3.5 方法的獲取和調(diào)用

一般情況下,要獲取Lua中的某個(gè)Function主要是用于對(duì)其進(jìn)行調(diào)用。假設(shè)有一個(gè)Lua方法定義如下:

function printHelloWorld()?

?print("Hello World");

end

那么,OC中則可以進(jìn)行下面操作來調(diào)用方法并傳遞參數(shù),最終取得返回值然后打印到控制臺(tái):

lua_getglobal(self.state, "printHelloWorld");

lua_pcall(self.state, 0, 0, 0);

上述代碼中的lua_pcall方法表示將棧中的元素視作Function來進(jìn)行調(diào)用。其中第二個(gè)參數(shù)為傳入?yún)?shù)的數(shù)量,必須與壓棧的參數(shù)數(shù)量一致;第三個(gè)參數(shù)為返回值的數(shù)量,表示調(diào)用后其放入棧中的返回值有多少個(gè)。第四個(gè)參數(shù)是用于發(fā)生錯(cuò)誤處理時(shí)的代碼返回。其運(yùn)行原理如下圖所示:


oc調(diào)用lua過程

大概過程是:lua_getglobal先把lua函數(shù)入棧,在oc中把要傳給lua的參數(shù)也入棧;然后lua_pcall將棧中的元素視作Function來進(jìn)行調(diào)用,調(diào)用完畢后清空棧,然后將lua函數(shù)的返回值放回棧中

舉例說明

假設(shè)有一個(gè)加法的Lua方法,其定義如下:

function add(a, b)

?return a + b;

end

那么,OC中則可以進(jìn)行下面操作來調(diào)用方法并傳遞參數(shù),最終取得返回值然后打印到控制臺(tái):

lua_getglobal(self.state, "add");

lua_pushinteger(self.state, 1000);

lua_pushinteger(self.state, 24);

lua_pcall(self.state, 2, 1, 0);

NSInteger retVal = lua_tonumber(self.state, -1);

NSLog(@"retVal = %ld", retVal);

3.6 Table的獲取和遍歷

Table的獲取跟其他變量一樣,一旦放入棧后可以根據(jù)需要通過調(diào)用lua_getfield方法來指定的key的值。如:

//假設(shè)Lua中有一個(gè)Table變量aa = {key1=1000, key2=24};

lua_getglobal(self.state, "aa");

lua_getfield(self.state, -1, "key2");

NSInteger value = lua_tonumber(self.state, -1);

NSLog(@"value = %ld", value);

lua_pop(self.state, 1);

如果Table是聲明時(shí)沒有指定key,那么則需要調(diào)用lua_rawgeti來獲取Table的值。如:

//假設(shè)Lua中有一個(gè)Table變量aa = {1000, 24};

lua_getglobal(self.state, "aa");

lua_rawgeti(self.state, -1, 2);

NSInteger value = lua_tonumber(self.state, -1);

NSLog(@"value = %ld", value);

lua_pop(self.state, 1);

有時(shí)候,Table存儲(chǔ)的信息會(huì)在函數(shù)體外被訪問,那么我們需要對(duì)Table進(jìn)行遍歷然后把它放入一個(gè)字典中,然后提供給程序使用。代碼如下:

//假設(shè)Lua中有一個(gè)Table變量aa = {1000, 24};

lua_getglobal(self.state, "aa");

lua_pushnil(self.state);

while (lua_next(self.state, -2)){

? NSInteger value = lua_tonumber(self.state, -1);

? if (lua_type(self.state, -2) == LUA_TSTRING) {

? ? const char *key = lua_tostring(self.state, -2);

? ? NSLog(@"key = %s, value = %ld", key, value);

? }

? else if (lua_type(self.state, -2) == LUA_TNUMBER) {

? ? NSInteger key = lua_tonumber(self.state, -2);

? ? NSLog(@"key = %ld, value = %ld", key, value);

? }

? lua_pop(self.state, 1);

}

上述代碼利用lua_next方法來遍歷Table的所有元素,該方法從棧頂彈出一個(gè)元素作為遍歷Table的起始Key,然后把每個(gè)元素的Key和Value放入棧中。為了遍歷所有元素所以起始的Key設(shè)置了一個(gè)nil值,證明要從Table最開始的Key進(jìn)行遍歷。如圖:


值得注意的是,在獲取Key值時(shí),最好先判斷Key的類型,然后再根據(jù)其對(duì)應(yīng)類型調(diào)用相應(yīng)的lua_toXXX方法。否則,因?yàn)閘ua_toXXX系列方法會(huì)對(duì)元素值進(jìn)行類型轉(zhuǎn)換,如整型的Key被lua_tostring轉(zhuǎn)換為String后再給到lua_next進(jìn)行遍歷就會(huì)報(bào)找不到指定Key的錯(cuò)誤。

最后編輯于
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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