Skip to content

API文档_iOS OS X_Objective C_LSCContext

vimfung edited this page Nov 15, 2018 · 20 revisions

API文档 > 类目录 > LSCContext

LSCContext

Summary

LuaScriptCore框架的核心类型之一,想要让iOS/OS X原生代码与lua进行交互则必须由这个上下文对象来管理所有的交互细节。其封装了一系列的方法用于简化桥接过程,不需要使用者熟悉lua的c api接口。只要像平时编写代码一样实现业务逻辑即可。同时,每个LSCContext对象所维护的lua环境是相对独立的,不能进行数据上的共享。

继承

LSCContext > NSObject

Constructor

init

LSCContext只带有默认构造方法,不需要传递任何参数,初始化后即可调用相关的实例方法来实现交互。

Instance Methods

addSearchPath:

添加搜索路径。在lua脚本中当使用require来引用其他lua脚本时,默认情况下,lua解析器只会查找一些内置的搜索路径(如lua解析器所在目录,系统库目录等)。如果引用的脚本不在这些内置目录中则会提示无法找到对应的脚本文件。这时候就需要使用此方法来添加一个搜索路径,让解析器可以在指定的路径下查找lua脚本文件。

LSCContext中默认添加了应用包目录作为搜索路径(即[[NSBundle mainBundle] resourcePath])。

声明
- (void)addSearchPath:(NSString *)path;
参数
  • path: 需要搜索的绝对路径地址。
示例
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
[self addSearchPath:resourcePath];

evalScriptFromString:

将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]);

evalScriptFromFile:

通过传入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]);

callMethodWithName:arguments:

使用该方法可以在原生层让一个lua层的方法进行调用执行并返回结果,传入方法名称和参数即可。其中方法的每个参数要求封装到一个LSCValue对象中,并且添到一个NSArray类型中传入给方法,数组的元素位置表示参数的顺序(下标0的元素表示方法第一个参数,下标1表示第二个参数,如此类推)。

对于registerMethodWithName:block:注册到lua的方法,同样可以使用该方法进行调用。

声明
- (LSCValue *)callMethodWithName:(NSString *)methodName arguments:(NSArray<LSCValue *> *)arguments;
参数
  • methodName: 方法名称,全局方法可以直接写方法名,如果是某个对象/Table中的方法可以使用xxx:methodNamexxx.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]);

registerMethodWithName:block:

将一段原生层的处理逻辑注册为一个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);

onException:

在lua脚本执行过程中可能会产生一些异常,通过该方法可以对产生的异常进行捕获并处理,同时也方便在开发过程中的调试工作。

该方法要求传入一个异常处理方法LSCExceptionHandler,其声明如下:

typedef void (^LSCExceptionHandler) (NSString *message);
声明
- (void)onException:(LSCExceptionHandler)handler;
参数
  • handler: 异常的处理方法
示例

下例是将lua中的异常输出到日志中进行查看,这样可以方便开发中的调试工作。

[context onException:^(NSString *message) {

    NSLog(@"lua exception = %@", message);

}];

raiseExceptionWithMessage:

在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;
    }
}];

setGlobalWithValue:forName:

为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

getGlobalForName:

通过变量名称来获取lua层中全局变量的值。返回值会封装在LSCValue对象中返回给原生层。

声明
- (LSCValue *)getGlobalForName:(NSString *)name;
参数
  • name: 变量名称
返回值

封装成LSCValue对象返回全局变量的值。

示例

下面例子演示获取lua中的全局变量msg并打印

LSCValue *value = [context getGlobalForName:@"msg"];
NSLog(@"value = %@", [value toString]);

retainValue:

用于保留lua层变量的引用,延长其生命周期。在一般情况下,lua和原生两层变量有着不同且独立的内存管理方式,因此为了避免在原生层操作lua层变量时,lua层已对变量进行内存释放所带来的异常,就要使用该方法来保留lua层对变量的引用,直到原生层调用releaseValue:方法后进行释放。最常见的情况是原生层引用lua层以local声明的function来进行回调。

记得注意的是,调用该方法引用变量,会以引用次数来维护该变量的生命周期,即调用了多少次retainValue:方法,就需要对应次数的releaseValue:方法才能对变量进行内存释放。同时,被引用的是lua的变量而非传入的LSCValue对象,所以不同的LSCValue对象封装相同的变量,其引用次数会累计在同一个变量上。

该方法只适用于functiontableuserdata以及导出类型对象实例。

声明
- (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];
}];

releaseValue:

retainValue:方法相对应,用于释放被引用的lua变量。每次调用都会使变量的引用次数减1,直到引用次数为0时,对象被释放。

声明
- (void)releaseValue:(LSCValue *)value;
参数
  • value: 需要释放的变量
Clone this wiki locally