本項(xiàng)目提供的庫(kù)是基于XCode 8.0進(jìn)行編譯的,如果想要要低于XCode 8.0上能夠成功編譯,需要進(jìn)行庫(kù)的重新編譯,請(qǐng)根據(jù)下面的步驟實(shí)現(xiàn):
LuaScriptCore中提供了LSCContext(Swift中為L(zhǎng)uaContext)這個(gè)上下文對(duì)象類(lèi)來(lái)維護(hù)整個(gè)Lua的環(huán)境,所以使用LuaScriptCore的第一步就是對(duì)Context進(jìn)行初始化。如:
Objective-C中
LSCContext *context = [[LSCContext alloc] init];
Swift中
var _context : LuaContext = LuaContext();
初始化完畢后才能進(jìn)行下面的各種操作。
原生層中要操作Lua中的變量或者方法,通常使用到的就是組織Lua腳本來(lái)進(jìn)行一些列的Lua操作(LuaScriptCore屏蔽了Lua庫(kù)中的C Api,目的是讓代碼更加接近原生,使用起來(lái)更加得心應(yīng)手),然后交由Context進(jìn)行腳本的解析。如:
Objective-C中
[self.context evalScriptFromString:@"print('Hello World');"];
Swift中
_context.evalScript(script: "print('Hello World');");
對(duì)于一些耗時(shí)或者Lua無(wú)法實(shí)現(xiàn)的功能(如:手機(jī)設(shè)備的拍照),都可以考慮交由原生層來(lái)實(shí)現(xiàn),然后提供接口讓Lua進(jìn)行調(diào)用。如下面獲取手機(jī)設(shè)備信息的方法:
如果是Objective-C項(xiàng)目,在Objective-C代碼中定義方法
[self.context registerMethodWithName:@"getDeviceInfo" block:^LSCValue *(NSArray *arguments) {
NSMutableDictionary *info = [NSMutableDictionary dictionary];
[info setObject:[UIDevice currentDevice].name forKey:@"deviceName"];
[info setObject:[UIDevice currentDevice].model forKey:@"deviceModel"];
[info setObject:[UIDevice currentDevice].systemName forKey:@"systemName"];
[info setObject:[UIDevice currentDevice].systemVersion forKey:@"systemVersion"];
return [LSCValue dictionaryValue:info];
}];
如果是Swifit項(xiàng)目,則在Swifit代碼中定義方法
_context.registerMethod(methodName: "getDeviceInfo", block: { (arguments : Array<LuaValue>) -> LuaValue in
var info : Dictionary<String, String> = Dictionary<String, String>();
info["deviceName"] = UIDevice.current.name;
info["deviceModel"] = UIDevice.current.model;
info["systemName"] = UIDevice.current.systemName;
info["systemVersion"] = UIDevice.current.systemVersion;
return LuaValue(dictionaryValue: info);
});
在Lua代碼中調(diào)用方法
local tbl = getDeviceInfo();
有時(shí)候需要通過(guò)調(diào)用Lua中的方法來(lái)取得返回值(在原生層中只能取得一個(gè)返回值),然后再做后續(xù)的處理,例如:
在Lua代碼中有add方法的定義
function add (a, b)
return a+b;
end
如果是Objective-C項(xiàng)目,在Objective-C代碼中通過(guò)context調(diào)用Lua方法
LSCValue *value = [self.context callMethodWithName:@"add"
arguments:@[[LSCValue integerValue:1000],
[LSCValue integerValue:24]]];
NSLog(@"result = %@", [value toNumber]);
如果是Swift項(xiàng)目,在Swift代碼中通過(guò)context調(diào)用Lua方法
let retValue : LuaValue? = _context.callMethod(methodName: "add",
arguments: [LuaValue(intValue: 1000), LuaValue(intValue:24)]);
if (retValue != nil)
{
NSLog("result = %d", retValue!.intValue);
}
LSCContext(Swift中為L(zhǎng)uaContext)所定義的方法都是全局的,有時(shí)候需要對(duì)一系列的方法進(jìn)行一個(gè)包裝,希望這些方法都?xì)w類(lèi)在某個(gè)模塊下,一來(lái)方便根據(jù)模塊來(lái)劃分方法的功能,二來(lái)可以避免名稱(chēng)的沖突。因此,可以使用LSCModule來(lái)對(duì)Lua的功能進(jìn)行擴(kuò)展。需要根據(jù)下面步驟實(shí)現(xiàn):
下面例子定義了一個(gè)日志模塊,如:
在Objective-C代碼中定義LSCModule的子類(lèi)
/**
* 日志模塊
*/
@interface LogModule : LSCModule
/**
* 寫(xiě)入日志
*
* @param message 日志信息
*/
+ (void)writeLog:(NSString *)message;
@end
@implementation LogModule
+ (void)writeLog:(NSString *)message
{
NSLog(@"** message = %@", message);
}
@end
注冊(cè)模塊
[self.context registerModuleWithClass:[LogModule class]];
如果你的是Swift項(xiàng)目,則可以在Swift代碼中進(jìn)行如下定義
class LogModule: LSCModule
{
static func writeLog(message : String) -> Void
{
NSLog("** message = %@", message);
}
}
然后注冊(cè)模塊
_context.registerModule(moduleClass: LogModule.self);
在Lua代碼中調(diào)用
LogModule.writeLog('Hello Lua Module!');
Lua中沒(méi)有明確的面向?qū)ο筇匦?,LuaScriptCore提供了一個(gè)面向?qū)ο蟮臄U(kuò)展,Lua可以簡(jiǎn)單地封裝類(lèi)型,并且進(jìn)行類(lèi)型實(shí)例的使用。首先需要先注冊(cè)面向?qū)ο蟮哪K類(lèi)LSCObjectClass(如果原生層有繼承于LSCObjectClass類(lèi)的子類(lèi)需要注冊(cè)時(shí),該步驟可省略),如:
Objective-C中
[self.context registerModuleWithClass:[LSCObjectClass class]];
Swift中
_context.registerModule(moduleClass: LSCObjectClass.self);
注冊(cè)成功后,可以直接在Lua中定義類(lèi)型,如:
Object.subclass("MyClass");
-- 重寫(xiě)類(lèi)型的初始化方法
function MyClass:init ()
print("MyClass instance initialize...");
end
-- 定義類(lèi)型屬性
MyClass.property = 0;
local instance = MyClass.create();
print (instance.property);
上述代碼的subclass就是子類(lèi)化對(duì)象方法,其接收一個(gè)類(lèi)型名稱(chēng)參數(shù),調(diào)用后會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)名稱(chēng)的類(lèi)型。該類(lèi)型擁有Object的所有特性。
對(duì)于Lua的類(lèi)定義有如下設(shè)定:
- 所有類(lèi)型的根類(lèi)是Object,這個(gè)注冊(cè)LSCObjectClass后會(huì)有這個(gè)類(lèi)的定義.
- 必須使用subclass方法來(lái)進(jìn)行子類(lèi)化,必須傳入一個(gè)有效并且不重復(fù)的類(lèi)型名稱(chēng)參數(shù)。
- 必須使用類(lèi)型的create方法進(jìn)行類(lèi)對(duì)象的實(shí)例化。
- 類(lèi)型中的方法(即類(lèi)方法)都以.號(hào)進(jìn)行調(diào)用,類(lèi)實(shí)例中的方法都以:號(hào)進(jìn)行調(diào)用。類(lèi)型和實(shí)例的屬性都以.號(hào)進(jìn)行訪問(wèn)。
- 每個(gè)類(lèi)中都有一個(gè)叫super的屬性來(lái)指代其父類(lèi)型。
- 需要調(diào)用父類(lèi)方法時(shí),請(qǐng)使用"類(lèi)型.super.method"方式進(jìn)行調(diào)用,如:
MyClass.super.test();
。- 當(dāng)類(lèi)實(shí)例對(duì)象初始化時(shí)會(huì)觸發(fā)init方法,銷(xiāo)毀時(shí)會(huì)觸發(fā)destroy方法,可以通過(guò)重寫(xiě)這些方法來(lái)進(jìn)行一些額外的工作。
如果需要讓原生類(lèi)直接映射到Lua中,按照下面步驟實(shí)現(xiàn):
如在OC中有如下類(lèi)型定義
@interface LSCTPerson : LSCObjectClass
@property (nonatomic, copy) NSString *name;
+ (NSString *)moduleName;
+ (void)printPersonName:(LSCTPerson *)person;
- (void)speak;
- (void)walk;
@end
@implementation LSCTPerson
+ (NSString *)moduleName
{
//變更導(dǎo)出的類(lèi)型名稱(chēng)
return @"Person";
}
+ (void)printPersonName:(LSCTPerson *)person
{
NSLog(@"Person name = %@", person.name);
}
- (void)speak
{
NSLog(@"%@ speak", self.name);
}
- (void)walk
{
NSLog(@"%@ walk", self.name);
}
@end
然后對(duì)該類(lèi)型進(jìn)行注冊(cè):
[self.context registerModuleWithClass:[LSCTPerson class]];
在Swift中可以如下定義
class LSCTPerson: LSCObjectClass
{
static override func moduleName() -> String
{
return "Person";
}
static func printPersonName(p : LSCTPerson) -> Void
{
NSLog("%@", p.name);
}
var name : String? = nil;
func speak() -> Void
{
NSLog("%@ speak", name ?? "noname");
}
func walk() -> Void
{
NSLog("%@ walk", name ?? "noname");
}
}
然后對(duì)該類(lèi)型進(jìn)行注冊(cè):
_context.registerModule(moduleClass: LSCTPerson.self);
注冊(cè)成功后,在lua中即可使用該類(lèi)型:
local person = Person.create();
person:setName("vimfung");
person:walk();
person:speak();
Person.printPersonName(person);
更多建議: