剛來(lái)新公司的第一天就要加班凯旭,一臉的苦逼坯墨。還好這是被安排研究一下OC和js的交互,對(duì)于這個(gè)apple新推出的庫(kù)還沒(méi)接觸過(guò)权逗,所以就在這里做一個(gè)簡(jiǎn)單的記錄美尸。
JavaScriptCore簡(jiǎn)介
iOS 7中加入了JavaScriptCore框架。該框架讓Objective-C和JavaScript代碼直接的交互變得更加的簡(jiǎn)單方便斟薇。而且使得js可以脫離webview與oc交互师坎。
在項(xiàng)目中引入JavaScriptCore后,鏈到頭文件中堪滨,除了大段的Copyright注釋可以看到里面只要引入了5個(gè)文件胯陋,每個(gè)文件里都定義跟文件名對(duì)應(yīng)的類(lèi):
JSContext和JSValue
<a style = "color:red; font: bold;">JSContext</a>
//JSVirtualMachine為JavaScript的運(yùn)行提供了底層資源,JSContext就為其提供著運(yùn)行環(huán)境,該方法用來(lái)執(zhí)行一段
//JS代碼椿猎,并且如果其中有方法惶岭、變量等信息都會(huì)被存儲(chǔ)在其中以便在需要的時(shí)候使用。
- (JSValue *)evaluateScript:(NSString *)script
//JSContext的創(chuàng)建都是基于JSVirtualMachine,如果是使用- (id)init;
//進(jìn)行初始化犯眠,那么在其內(nèi)部會(huì)自動(dòng)創(chuàng)建一個(gè)新的JSVirtualMachine
//對(duì)象然后調(diào)用前邊的初始化方法
- (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine;
<a style = "color:red; font: bold;">JSValue</a>
則可以說(shuō)是JavaScript和Object-C之間互換的橋梁按灶,它提供了多種方法可以方便地把JavaScript數(shù)據(jù)類(lèi)型轉(zhuǎn)換成Objective-C,或者是轉(zhuǎn)換過(guò)去筐咧。其一一對(duì)應(yīng)方式可見(jiàn)下表:
基本類(lèi)型的轉(zhuǎn)換
JSContext *context = [[JSContext alloc] init];
JSValue *jsVal = [context evaluateScript:@"2+7"];
int iVal = [jsVal toInt32];
NSLog(@"JSValue: %@, int: %d", jsVal, iVal);
//輸出9
還可以存一個(gè)Js變量在JSContext中鸯旁,然后通過(guò)下標(biāo)取出來(lái)。對(duì)于數(shù)組或者對(duì)象類(lèi)型量蕊,JSValue也可以通過(guò)下表直接取值和賦值.
[context evaluateScript:@"var arr = [21, 7 ,'leo']"];
JSValue *value = context[@"arr"];
value[1] = @"blog";
value[7] = @7;
NSArray *array = [value toArray];
打印數(shù)組看一下
Printing description of array:
<__NSArrayM 0x7fabc144ea40>(
21,
blog,
leo,
<null>,
<null>,
<null>,
<null>,
7
代碼成功把數(shù)據(jù)從OC?賦值到了Js數(shù)組上铺罢,而且jsValue遵循js數(shù)組的特性,無(wú)下標(biāo)越位残炮,自動(dòng)延展數(shù)組大小
方法的轉(zhuǎn)換(js調(diào)用oc的第一種方法)
各種數(shù)據(jù)類(lèi)型可以轉(zhuǎn)換韭赘,Objective-C的Block也可以傳入JSContext中當(dāng)做JavaScript的方法使用。
context[@"add"] = ^(NSInteger a, NSInteger b){
//獲取該方法的對(duì)象
JSValue *v = [JSContext currentThis];
//獲取當(dāng)前的參數(shù)
NSArray *args = [JSContext currentArguments];
NSLog(@"當(dāng)前對(duì)象:%@",v);
NSLog(@"當(dāng)前參數(shù):%@",args);
NSLog(@"和是%ld",a + b);
};
[context evaluateScript:@"add(1,2)"];
輸出如下:
當(dāng)前對(duì)象:GlobalObject
當(dāng)前參數(shù):(
1,
2)
和是3
上邊的例子中對(duì)于"this"輸出的內(nèi)容是GlobalObject势就,這也是JSContext對(duì)象方法- (JSValue *)globalObject;所返回的內(nèi)容泉瞻。因?yàn)槲覀冎涝贘avaScript里脉漏,所有全局變量和方法其實(shí)都是一個(gè)全局變量的屬性,在瀏覽器中是window袖牙,在JavaScriptCore是什么就不得而知了侧巨。
Block可以傳入JSContext作方法,但是JSValue沒(méi)有toBlock方法來(lái)把JavaScript方法變成Block在Objetive-C中使用鞭达。畢竟Block的參數(shù)個(gè)數(shù)和類(lèi)型已經(jīng)返回類(lèi)型都是固定的司忱。雖然不能把方法提取出來(lái),但是JSValue提供了- (JSValue *)callWithArguments:(NSArray *)arguments;方法可以反過(guò)來(lái)將參數(shù)傳進(jìn)去來(lái)調(diào)用方法畴蹭。
JSContext *context = [[JSContext alloc]init];
NSString *js = @"function add(a,b){return a+ b;}";
[context evaluateScript:js];
JSValue *value = [context[@"add"] callWithArguments:@[@3,@4]];
NSLog(@"%@",value);
輸出如下:
7
JSValue還提供
- (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments;
讓我們可以直接簡(jiǎn)單地調(diào)用對(duì)象上的方法坦仍。只是如果定義的方法是全局函數(shù),那么很顯然應(yīng)該在JSContext的globalObject對(duì)象上調(diào)用該方法撮胧;如果是某JavaScript對(duì)象上的方法桨踪,就應(yīng)該用相應(yīng)的JSValue對(duì)象調(diào)用。