iOS 7中苹果正式开放加入了JavaScriptCore框架。该框架让Objective-C和JavaScript 直接进行交互 。这个框架其实只是基于WebKit实现的JavaScriptCore的的一个包装
要使用JavaScriptCore,首先我们需要引入它的头文件
#import
这个框架主要包括五个对象:
#import "JSContext.h" //提供运行环境
#import "JSValue.h" //是JSContext执行后的返回结果,他包括多种类型(比如基本数据类型和函数类型,对象类型等)
#import "JSManagedValue.h" //是JSValue的封装
#import "JSVirtualMachine.h" //提供了底层资源
#import "JSExport.h" //是一种协议
JSContext对象
在OC中初始化JSContext对象,可以直接init初始化,也可根据当前webView的键获取到jscontext
// init初始化JSContext对象
JSContext *context = [[JSContext alloc] init];
//创建JSContext 对象(通过当前webView的键获取到JSContext)
JSContext *context=[self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
通过JSContext对象调用js代码,这里是一个弹窗测试:
1.OC直接拼写,实现js弹窗
NSString *alertJS=@"alert('test js OC')"; //准备执行的js代码
[context evaluateScript:alertJS];//通过oc方法调用js的alert
2.引入js文件,调用js中的方法,实现js弹窗
//html代码
//在 index.html中加入js文件
//引入js
SimonLike
//js代码
// test.js文件中方法
function jsalert(test){
alert(test);
}
//OC代码
//在OC中找到html的路径转换格式,用UIWebView进行加载,这个时候js文件、css文件也一起加了进来;
- (void)loadHtml {
//创建webview
CGRect webViewRect = CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height - 64);
self.webView = [[UIWebView alloc] initWithFrame:webViewRect];
self.webView.backgroundColor = [UIColor lightGrayColor];
self.webView.scalesPageToFit = YES;
self.webView.delegate = self;
[self.view addSubview:self.webView];
//webview加载html
NSString * htmlPath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];
NSURL *url = [NSURL fileURLWithPath:htmlPath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
//在webview加载完成后,调用js文件中的方法,
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *alertJS=@"jsalert('test js OC')"; //准备执行的js代码
[context evaluateScript:alertJS];//通过oc方法调用js的alert
}
js调用iOS中OC方法;其中jscandoiOS就是js的方法名称,赋给是一个block 里面是iOS代码,注意事项:1,在block中避免循环引用,我们一般会对self进行弱化;2,在block中直接调用OC方法,可能会导致异常或崩溃,所以为了避免异常或崩溃 js调用oc方法时 放在GCD中 进行异步操作;
//OC中拼接,没有加载js文件写法
[context evaluateScript:@"jscandoiOS(tag)"];
//加载js文件写法
function jscandoiOS(tag){
}
__weak typeof(self)weakSelf = self;//避免循环引用 弱化
context[@"jscandoiOS"] = ^(JSValue *value){
NSString *str = value.toString;//把接收到的JSValue对象转换OC中的NSString类型
dispatch_async(dispatch_get_main_queue(), ^{//在GCD中 进行异步操作
switch (str.integerValue) {
case 0:{//iOS
// you can do ...
}
break;
...
default:
break;
}
});
};
JSValue对象
上面代码中,点击js方法“jscandoiOS”在iOS中能监听到并做出相应处理,在iOS这边接收到js所传值为JSValue对象,然后转换为OC中的NSString;对于JSValue对象转换OC类型的方法很多:
- (id)toObject;
- (BOOL)toBool;
- (double)toDouble;
- (int32_t)toInt32;
- (NSString *)toString;
- (NSArray *)toArray;
- (id)toObject;
- (NSDictionary *)toDictionary;
...
JSExport对象
JSExport是一个协议,很方便的让JavaScript能够访问和操作Objective-C对象。
1,自定义个协议(JSExportTest)继承自JSExprot,并定义需要暴露给js的属性和方法,例:
@protocol JSExportTest
- (NSString *)personName;//暴露给js调用
@end
2,新建一个类对象,实现协议和方法,例:
person.h
#import "JSExportTest.h"
@interface person : NSObject
@end
person.m
#import "person.h"
@implementation person
- (NSString *)personName{
return @"this is OC";
}
@end
3,js方法调用
-(void)jsJSExport {
person *p = [[person alloc]init];
context[@"person"] = p;
JSValue *value = [context evaluateScript:@"person.personName()"];
NSLog(@"context->%@",value);
}
打印结果: context->this is OC
JSVirtualMachine对象
一个 JSVirtualMachine可以运行多个context,由于都是在同一个堆内存和同一个垃圾回收下,相互之间传值是没问题的。如果在不同的JSVirtualMachine传值,垃圾回收就不知道他们之间的关系了,可能会引起异常。
JSVirtualMachine有两个方法:一个是保存JSValue对象,一个是移除JSValue对象:
//保存
- (void)addManagedReference:(id)object withOwner:(id)owner;
//移除
- (void)removeManagedReference:(id)object withOwner:(id)owner;
JSVirtualMachine对象
引入:http://www.jianshu.com/p/bbfa8dee967e
JavaScriptCore中引入了JSManagedValue类型,该类型主要是作为一个引用桥接,将JSValue转为JSManagedValue类型后,可以添加到JSVirtualMachine对象中,这样能够保证你在使用过程中JSValue对象不会被释放掉,当你不再需要该JSValue对象后,从JSVirtualMachine中移除该JSManagedValue对象,JSValue对象就会被释放并置空。
大家不要被这么多对象类型搞晕了,简单一点说,JSVirtualMachine就是一个用于保存弱引用对象的数组,加入该数组的弱引用对象因为会被该数组retain,所以保证了使用时不会被释放,当数组里的对象不再需要时,就从数组中移除,没有了引用的对象就会被系统释放。
异常处理
context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
[JSContext currentContext].exception = exception;
NSLog(@"exception:%@",exception);
};