刚来新公司的第一天就要加班,一脸的苦逼。还好这是被安排研究一下OC和js的交互,对于这个apple新推出的库还没接触过,所以就在这里做一个简单的记录。
JavaScriptCore简介
iOS 7中加入了JavaScriptCore框架。该框架让Objective-C和JavaScript代码直接的交互变得更加的简单方便。而且使得js可以脱离webview与oc交互。
在项目中引入JavaScriptCore后,链到头文件中,除了大段的Copyright注释可以看到里面只要引入了5个文件,每个文件里都定义跟文件名对应的类:
JSContext和JSValue
<a style = "color:red; font: bold;">JSContext</a>
//JSVirtualMachine为JavaScript的运行提供了底层资源,JSContext就为其提供着运行环境,该方法用来执行一段
//JS代码,并且如果其中有方法、变量等信息都会被存储在其中以便在需要的时候使用。
- (JSValue *)evaluateScript:(NSString *)script
//JSContext的创建都是基于JSVirtualMachine,如果是使用- (id)init;
//进行初始化,那么在其内部会自动创建一个新的JSVirtualMachine
//对象然后调用前边的初始化方法
- (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine;
<a style = "color:red; font: bold;">JSValue</a>
则可以说是JavaScript和Object-C之间互换的桥梁,它提供了多种方法可以方便地把JavaScript数据类型转换成Objective-C,或者是转换过去。其一一对应方式可见下表:
基本类型的转换
JSContext *context = [[JSContext alloc] init];
JSValue *jsVal = [context evaluateScript:@"2+7"];
int iVal = [jsVal toInt32];
NSLog(@"JSValue: %@, int: %d", jsVal, iVal);
//输出9
还可以存一个Js变量在JSContext中,然后通过下标取出来。对于数组或者对象类型,JSValue也可以通过下表直接取值和赋值.
[context evaluateScript:@"var arr = [21, 7 ,'leo']"];
JSValue *value = context[@"arr"];
value[1] = @"blog";
value[7] = @7;
NSArray *array = [value toArray];
打印数组看一下
Printing description of array:
<__NSArrayM 0x7fabc144ea40>(
21,
blog,
leo,
<null>,
<null>,
<null>,
<null>,
7
代码成功把数据从OC�赋值到了Js数组上,而且jsValue遵循js数组的特性,无下标越位,自动延展数组大小
方法的转换(js调用oc的第一种方法)
各种数据类型可以转换,Objective-C的Block也可以传入JSContext中当做JavaScript的方法使用。
context[@"add"] = ^(NSInteger a, NSInteger b){
//获取该方法的对象
JSValue *v = [JSContext currentThis];
//获取当前的参数
NSArray *args = [JSContext currentArguments];
NSLog(@"当前对象:%@",v);
NSLog(@"当前参数:%@",args);
NSLog(@"和是%ld",a + b);
};
[context evaluateScript:@"add(1,2)"];
输出如下:
当前对象:GlobalObject
当前参数:(
1,
2)
和是3
上边的例子中对于"this"输出的内容是GlobalObject,这也是JSContext对象方法- (JSValue *)globalObject;所返回的内容。因为我们知道在JavaScript里,所有全局变量和方法其实都是一个全局变量的属性,在浏览器中是window,在JavaScriptCore是什么就不得而知了。
Block可以传入JSContext作方法,但是JSValue没有toBlock方法来把JavaScript方法变成Block在Objetive-C中使用。毕竟Block的参数个数和类型已经返回类型都是固定的。虽然不能把方法提取出来,但是JSValue提供了- (JSValue *)callWithArguments:(NSArray *)arguments;方法可以反过来将参数传进去来调用方法。
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;
让我们可以直接简单地调用对象上的方法。只是如果定义的方法是全局函数,那么很显然应该在JSContext的globalObject对象上调用该方法;如果是某JavaScript对象上的方法,就应该用相应的JSValue对象调用。