-
Notifications
You must be signed in to change notification settings - Fork 115
API文档_iOS OS X_Objective C_LSCContext
LuaScriptCore框架的核心类型之一,想要让iOS/OS X原生代码与lua进行交互则必须由这个上下文对象来管理所有的交互细节。其封装了一系列的方法用于简化桥接过程,不需要使用者熟悉lua的c api接口。只要像平时编写代码一样实现业务逻辑即可。同时,每个LSCContext对象所维护的lua环境是相对独立的,不能进行数据上的共享。
LSCContext
> NSObject
LSCContext只带有默认构造方法,不需要传递任何参数,初始化后即可调用相关的实例方法来实现交互。
添加搜索路径。在lua脚本中当使用require
来引用其他lua脚本时,默认情况下,lua解析器只会查找一些内置的搜索路径(如lua解析器所在目录,系统库目录等)。如果引用的脚本不在这些内置目录中则会提示无法找到对应的脚本文件。这时候就需要使用此方法来添加一个搜索路径,让解析器可以在指定的路径下查找lua脚本文件。
在LSCContext
中默认添加了应用包目录作为搜索路径(即[[NSBundle mainBundle] resourcePath]
)。
- (void)addSearchPath:(NSString *)path;
- path: 需要搜索的绝对路径地址。
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
[self addSearchPath:resourcePath];
将lua脚本内容以字符串形式传给LSCContext
来解析。这种方式使用灵活,可以在程序执行时动态生成脚本让上下文对象进行解析。脚本内容可以带有返回值(只要在内容最后写入return
关键字即可返回想要的结果),在方法执行完后,返回值会封装在LSCValue
对象中。
- (LSCValue *)evalScriptFromString:(NSString *)string;
- string: lua脚本字符串
脚本的返回值会被封装在LSCValue
对象中返回,开发者可以通过LSCValue来取得返回值并作后续的操作。
NSString *scriptText = @"return \"Hello World!\";";
LSCValue *retVal = [context evalScriptFromString:scriptText];
NSLog(@"retVal = %@", [retVal toString]);
通过传入lua脚本文件所在路径来解析脚本。传入路径分两种情况:如果脚本包含在应用包内,则可以通过传入相对路径来指定脚本路径。除了前面说到的情况外都必须传入绝对路径来指定脚本的位置。
- (LSCValue *)evalScriptFromFile:(NSString *)path;
- path: lua脚本文件所在路径
脚本的返回值会被封装在LSCValue
对象中返回,开发者可以通过LSCValue来取得返回值并作后续的操作。
NSString *scriptPath = [NSString stringWithFormat:@"%@/Documents/test.lua", NSHomeDirectory()];
LSCValue *retVal = [context evalScriptFromFile:scriptPath];
NSLog(@"retVal = %@", [retVal toString]);
使用该方法可以在原生层让一个lua层的方法进行调用执行并返回结果,传入方法名称和参数即可。其中方法的每个参数要求封装到一个LSCValue
对象中,并且添到一个NSArray
类型中传入给方法,数组的元素位置表示参数的顺序(下标0的元素表示方法第一个参数,下标1表示第二个参数,如此类推)。
对于registerMethodWithName:block:
注册到lua的方法,同样可以使用该方法进行调用。
- (LSCValue *)callMethodWithName:(NSString *)methodName arguments:(NSArray<LSCValue *> *)arguments;
- methodName: 方法名称,全局方法可以直接写方法名,如果是某个对象/
Table
中的方法可以使用xxx:methodName
或xxx.methodName
方式传入(其中xxx
为对象/Table
的名称)。 - arguments: 参数列表,所需参数先封装成
LSCValue
对象后放入NSArray
对象中,再统一传入方法。
方法的返回值会被封装在LSCValue
对象中返回,开发者可以通过LSCValue来取得返回值并作后续的操作。
假设lua中存在下面一个方法
function testMethod(msg)
return "say: " .. msg
end
原生层可以这样调用
NSArray<LSCValue *> *args = @[[LSCValue stringValue:@"Hello World"]];
LSCValue *retVal = [context callMethodWithName:@"testMethod" arguments:args];
NSLog(@"retVal = %@", [retVal toString]);
将一段原生层的处理逻辑注册为一个lua方法提供lua层调用。对于一些功能lua无法直接处理的(如调用手机的摄像头拍照),可以使用该方法让原生层来负责处理,并在lua层生成一个方法入口,让lua层在任何地方都可以调用。
其中原生处理逻辑也block形式传入给方法,其声明如下:
typedef LSCValue* (^LSCFunctionHandler) (NSArray<LSCValue *> *arguments);
- (void)registerMethodWithName:(NSString *)methodName block:(LSCFunctionHandler)block;
- methodName: 注册到lua层的方法名称。如果lua存在同名方法,则会被该操作覆盖之前的方法。
- block: 方法的处理逻辑。
[context registerMethodWithName:@"testMethod" block:^LSCValue* (NSArray<LSCValue *> *arguments) {
return [LSCValue stringValue:@"Hello World!"];
}];
lua中可以这样调用
local retVal = testMethod();
print (retVal);
在lua脚本执行过程中可能会产生一些异常,通过该方法可以对产生的异常进行捕获并处理,同时也方便在开发过程中的调试工作。
该方法要求传入一个异常处理方法LSCExceptionHandler
,其声明如下:
typedef void (^LSCExceptionHandler) (NSString *message);
- (void)onException:(LSCExceptionHandler)handler;
- handler: 异常的处理方法
下例是将lua中的异常输出到日志中进行查看,这样可以方便开发中的调试工作。
[context onException:^(NSString *message) {
NSLog(@"lua exception = %@", message);
}];
在lua层调用一个原生方法时,如果lua传入参数不符合规则或者在方法处理过程中出现一些错误,则不能让lua脚本继续向下执行,可以使用该方法来抛出一个lua的异常,让lua中断执行。需要注意的是,在抛出lua异常同时,该方法也会抛出一个原生异常,所以需要原生代码使用try-catch
来进行异常捕获。
- (void)raiseExceptionWithMessage:(NSString *)message;
- message: 抛出异常的消息内容。用于告知异常产生的原因。
下例通过在注册lua方法中判断lua是否有传入一个字符串参数给原生,如果没有则抛出异常。
[context registerMethodWithName:@"testMethod" block:^LSCValue* (NSArray<LSCValue *> *arguments) {
@try
{
if (arguments.count == 0 || arguments[0].valueType != LSCValueTypeString)
{
[context raiseExceptionWithMessage:@"argument invalid"];
}
NSString *msg = [arguments[0] toString];
return [LSCValue stringValue:[NSString stringWithFormat:@"say: %@", msg]];
}
@catch (NSException *exp)
{
return nil;
}
}];
为lua层的某个全局变量赋值,如果指定变量名称不存在则创建变量,如果存在则覆盖变量原有值。其中变量的值需要先封装到LSCValue
中再传给方法。
- (void)setGlobalWithValue:(LSCValue *)value forName:(NSString *)name;
- value: 变量的值
- name: 变量名称
在原生层中为lua的msg
全局变量赋值
LSCValue *value = [LSCValue stringValue:@"Hello World"];
[context setGlobalWithValue:value forName:@"msg"];
lua层中就可以对msg
变量进行使用
print(msg); -- 输出Hello World
通过变量名称来获取lua层中全局变量的值。返回值会封装在LSCValue
对象中返回给原生层。
- (LSCValue *)getGlobalForName:(NSString *)name;
- name: 变量名称
封装成LSCValue
对象返回全局变量的值。
下面例子演示获取lua中的全局变量msg
并打印
LSCValue *value = [context getGlobalForName:@"msg"];
NSLog(@"value = %@", [value toString]);
用于保留lua层变量的引用,延长其生命周期。在一般情况下,lua和原生两层变量有着不同且独立的内存管理方式,因此为了避免在原生层操作lua层变量时,lua层已对变量进行内存释放所带来的异常,就要使用该方法来保留lua层对变量的引用,直到原生层调用releaseValue:
方法后进行释放。最常见的情况是原生层引用lua层以local
声明的function
来进行回调。
记得注意的是,调用该方法引用变量,会以引用次数来维护该变量的生命周期,即调用了多少次retainValue:
方法,就需要对应次数的releaseValue:
方法才能对变量进行内存释放。同时,被引用的是lua的变量而非传入的LSCValue
对象,所以不同的LSCValue
对象封装相同的变量,其引用次数会累计在同一个变量上。
该方法只适用于function
、table
、userdata
以及导出类型对象实例。
- (void)retainValue:(LSCValue *)value;
- value: 需要引用的lua变量。
下例演示对lua传入的function对象进行引用
[context registerMethodWithName:@"testMethod" block:^LSCValue* (NSArray<LSCValue *> *arguments) {
if (arguments.count > 0 && arguments[0].valueType == LSCValueTypeFunction)
{
[context retainValue:arguments[0]];
}
return [LSCValue nilValue];
}];
与retainValue:
方法相对应,用于释放被引用的lua变量。每次调用都会使变量的引用次数减1,直到引用次数为0时,对象被释放。
- (void)releaseValue:(LSCValue *)value;
- value: 需要释放的变量