iOS OS X平臺(tái)文檔

2018-01-18 12:04 更新

集成說(shuō)明

  1. 下載源碼到本地
  2. 打開(kāi)Release目錄,如果您的是OC項(xiàng)目,可根據(jù)需要運(yùn)行系統(tǒng)選擇iOS或者OSX目錄;如果您的是Swift項(xiàng)目,則可以根據(jù)運(yùn)行系統(tǒng)選擇iOS-Swift或者OSX-Swift目錄
  3. 直接拖動(dòng)目錄到XCode的工程下進(jìn)行導(dǎo)入,導(dǎo)入時(shí)記得勾選"Copy items if needed"。
  4. 導(dǎo)入成功后則可以正常使用LuaScriptCore了。

關(guān)于重新編譯的問(wèn)題

本項(xiàng)目提供的庫(kù)是基于XCode 8.0進(jìn)行編譯的,如果想要要低于XCode 8.0上能夠成功編譯,需要進(jìn)行庫(kù)的重新編譯,請(qǐng)根據(jù)下面的步驟實(shí)現(xiàn):

  1. 打開(kāi)Source/iOS_OSX/目錄中的LuaScriptCore項(xiàng)目文件。
  2. 選擇你想要重新編譯的平臺(tái),如果是iOS的OC版本則選擇LuaScriptCore-iOS-output的scheme,Swift版本則選擇LuaScriptCore-iOS-Swift-output的scheme;如果是OS X的OC版本則選擇LuaScriptCore-OSX-output的scheme,Swift版本則選擇LuaScriptCore-OSX-Swift-output的scheme。
  3. Command + B 進(jìn)行重新編譯,編譯后的庫(kù)文件和頭文件會(huì)放到Release目錄下替換原有的文件。

使用說(shuō)明

初始化LuaScriptCore

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中的變量或者方法,通常使用到的就是組織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');");

注冊(cè)一個(gè)原生方法給Lua調(diào)用

對(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();

調(diào)用一個(gè)Lua方法

有時(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);
}

模塊化擴(kuò)展

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):

  1. 新聲明一個(gè)模塊類(lèi)繼承于LSCModule類(lèi)(必須繼承于LSCModule類(lèi),否則無(wú)法進(jìn)行模塊注冊(cè))
  2. 在創(chuàng)建的模塊類(lèi)中定義需要導(dǎo)出到lua的類(lèi)方法(即+號(hào)方法,注:-號(hào)方法是不會(huì)進(jìn)行導(dǎo)出),聲明方法完全跟Objective-C/Swift的方法一樣(對(duì)于不想導(dǎo)出到Lua的方法可以在定義是使用下劃線“_”開(kāi)頭),但需要注意的是結(jié)構(gòu)體是無(wú)法作為參數(shù)或者返回值與Lua進(jìn)行交互。
  3. 調(diào)用LSContext的registerModuleWithClass方法(Swift中調(diào)用LuaContext的registerModule方法)將定義的類(lèi)型傳入即完成功能模塊的擴(kuò)展。

下面例子定義了一個(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面向?qū)ο?/h2>

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è)定:

  1. 所有類(lèi)型的根類(lèi)是Object,這個(gè)注冊(cè)LSCObjectClass后會(huì)有這個(gè)類(lèi)的定義.
  2. 必須使用subclass方法來(lái)進(jìn)行子類(lèi)化,必須傳入一個(gè)有效并且不重復(fù)的類(lèi)型名稱(chēng)參數(shù)。
  3. 必須使用類(lèi)型的create方法進(jìn)行類(lèi)對(duì)象的實(shí)例化。
  4. 類(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)。
  5. 每個(gè)類(lèi)中都有一個(gè)叫super的屬性來(lái)指代其父類(lèi)型。
  6. 需要調(diào)用父類(lèi)方法時(shí),請(qǐng)使用"類(lèi)型.super.method"方式進(jìn)行調(diào)用,如:MyClass.super.test();。
  7. 當(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):

  1. 定義一個(gè)新的類(lèi)繼承于LSCObjectClass類(lèi)。
  2. 定義新類(lèi)型的屬性和方法(注:原生類(lèi)中的屬性會(huì)轉(zhuǎn)換為L(zhǎng)ua類(lèi)中的setXXX和XXX方法),對(duì)于不想導(dǎo)出到Lua中的方法或?qū)傩钥梢栽诼暶鲿r(shí)使用下劃線“_”開(kāi)頭。
  3. 定義類(lèi)的類(lèi)方法會(huì)導(dǎo)出給類(lèi)型,定義實(shí)例方法會(huì)導(dǎo)出給類(lèi)型的實(shí)例。
  4. 調(diào)用LSContext的registerModuleWithClass方法(Swift中調(diào)用LuaContext的registerModule方法)將定義的類(lèi)型傳入即完成Lua類(lèi)的聲明。導(dǎo)入時(shí)可以直接導(dǎo)入子類(lèi),LSContext(或LuaContext)會(huì)檢測(cè)是否有導(dǎo)入根類(lèi)型。

如在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);

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)