http://www.jianshu.com/p/1328e15416f3/comments/1724404

javascript目前看来仍是世界上最流行的语言,不管在web、服务端还是客户端都有广泛的应用,很多跨平台方案也采用js来实现,比如著名的reactjs,苹果在iOS7引入了javascriptcore库,提供更简单方便的方式将js接入,iOS7之前要执行js操作只能通过UIWebview中的
stringByEvaluatingJavaScriptFromString方法,而且JavaScriptCore这块的代码开源,可以到这里查看,本文就简单介绍一下JavaScriptCore:

  • Objective-C调用JavaScript
  • JavaScript调用Objective-C
  • 内存管理
  • 多线程

不过在那之前先介绍几个基本概念:

  • JSContext
    一个JSContext实例代表着一个js运行时环境,js代码都需要在一个context上下文内执行,而且JSContext还负责管理js虚拟机中所有对象的生命周期
  • JSValue
    表示一个JavaScript的实体,一个JSValue可以表示很多JavaScript原始类型例如boolean, integers, doubles,甚至包括对象和函数。我们对JS的操作都是通过它,并且每个JSValue都强引用一个context。同时,OC和JS对象之间的转换也是通过它,相应的类型转换如下:

JSValue类型转换

  • JSVirtualMachine
    js代码运行的虚拟机,提供JavaScriptCore执行需要的资源,有自己独立的堆栈以及垃圾回收机制,而且通过锁来实现线程安全,如果需要并发执行js代码,可以创建不同的JSVirtualMachine虚拟机对象来实现;

Objective-C调用JavaScript

oc想要调用js代码的话,先创建一个JSContext对象实例,接着通过evaluateScript加载js代码到context对象中,然后获取js对象,如果为js函数对象,通过callWithArguments调用该js函数,并且可以以数组的方式传递参数。

  //test.jsvar appendString = function(name) { return 'string:' + name; }; var arr = [1, 2 , 'hello world']; //test.m NSString *jsPath = [[NSBundle mainBundle] pathForResource:@"test"ofType:@"js"]; NSString *jsContent = [NSString stringWithContentsOfFile:jsPath encoding:NSUTF8StringEncoding error:nil]; JSContext *context = [[JSContext alloc] init]; [context evaluateScript:jsContent]; JSValue *value = [context[@"appendString"] callWithArguments:@[@"hello"]]; JSValue *value1 = context[@"arr"]; NSLog(@"appendString:%@",[value toString] );//appendString:string:hello NSLog(@"arr:%@",[value1 toArray] ); // arr:( // 1, // 2, // "hello world" // )

JavaScript调用Objective-C

js调用oc有两种实现方式

  • Blocks方式
    我们可以通过block的方式将oc代码暴露给js,JavaScriptCore会自动将oc block包装在js函数中,我们就可以直接在js中调用该block函数,有点方便~
    JSContext *context = [[JSContext alloc] init];context[@"sayhi"] = ^(NSString *name) {NSLog(@"say hi to %@",name);};[context evaluateScript:@"sayhi('Greg')"]; //"say hi to Greg"

block.png

  • JSExport协议
    如果你到头文件中去查看JSExport协议,你会发现这个协议其实没有定义任何东西。JavaScriptCore提供这个协议用来将oc的方法跟属性暴露给js调用,其中@property会转换成js的getter和setter方法,实例方法会转换成js函数,而类方法则转换成js中global object的方法。

JSExport

举个例子简单说明一下,我们的PersonProtocol协议定义好要暴露给js的内容:

//定义需要暴露给js的内容,这里我们只暴露personName和queryPersonName接口
@protocol PersonProtocol <JSExport> @property(nonatomic,copy)NSString *personName; -(NSString *)queryPersonName; @end //Person实现PersonProtocol协议,而自己定义的age和queryPersonAge接口不暴露给js @interface Person : NSObject <PersonProtocol> @property(nonatomic,assign)NSInteger age; -(NSInteger)queryPersonAge; @end @implementation Person @synthesize personName = _personName; -(NSString *)queryPersonName{ return self.personName; } -(NSInteger)queryPersonAge{ return self.age; } @end JSContext *context = [[JSContext alloc] init]; //创建Person类的对象,将他赋值给js对象 Person *person=[Person new]; person.personName = @"Greg"; person.age = 27; context[@"person"]=person; //可以调用获取PersonProtocol暴露的内容 NSString *personName = [[context evaluateScript:@"person.personName"] toString]; //"Greg" NSString *personName1 = [[context evaluateScript:@"person.queryPersonName()"] toString]; //"Greg" //js无法调用跟age相关的内容 NSInteger age = [[context evaluateScript:@"person.age"] toInt32]; // 0 NSInteger age1 = [[context evaluateScript:@"person.queryPersonAge()"] toInt32]; //0

内存管理

下面我们来说说内存管理方面的问题,我们知道在oc中使用ARC方式管理内存(基于引用计数),但JavaScriptCore中使用的是垃圾回收方式,其中所有的引用都是强引用,我们不必担心其循环引用,js的垃圾回收能够打破这些强引用,通常我们在使用JavaScriptCore中的API时不太需要去关注内存问题,因为这些都会被自动处理好,不过有些情况需要我们注意一下:

  • 在oc对象中存储js的值
    如果在oc对象中存储js的值,需要注意一下不要导致循环引用,看个例子:
//test.js
function ClickHandler(button, callback) { this.button = button; this.handler = callback; } //test.m @implement MyButton -(void)setClickHandler:(JSValue*)handler { _onClickHandler = handler; //导致retain cycle }

上面的代码中可以看出,mybutton的onclickHandler强引用了js的handler,而js的button又强引用了mybutton,这就会导致retain cycle的问题:

retain cycle

在oc中为了打破循环引用我们采用weak的方式,不过在JavaScriptCore中我们采用内存管理辅助对象JSManagedValue的方式,它能帮助引用技术和垃圾回收这两种内存管理机制之间进行正确的转,所以我们可以采用如下方式:

@implement MyButton
-(void)setClickHandler:(JSValue*)handler
{_onClickHandler = [JSManagedValue managedValueWithValue:handler];[_context.virtualMachine addManagedReference:_onClickHandler];
}

JSManagedValue本身只弱引用js值,需要调用JSVirtualMachine的addManagedReference:withOwner:把它添加到JSVirtualMachine中,这样如果JavaScript能够找到该JSValue的Objective-C owner,该JSValue的引用就不会被释放。

  • block中捕获JSContexts
    我们知道block会默认强引用它所捕获的对象,如下代码所示,如果block中直接使用context也会造成循环引用,这使用我们最好采用[JSContext currentContext]来获取当前的JSContext:
//bad
JSContext *context = [[JSContext alloc] init];
context[@"callback"] = ^{JSValue *object = [JSValue valueWithNewObjectInContext:context]; return object; }; //good JSContext *context = [[JSContext alloc] init]; context[@"callback"] = ^{ JSValue *object = [JSValue valueWithNewObjectInContext: [JSContext currentContext]]; return object; };

多线程

JavaScriptCore中提供的API都是线程安全的,一个JSVirtualMachine在一个线程中,它可以包含多个JSContext,而且相互之间可以传值,为了确保线程安全,这些context在运行的时候会采用锁,可以认为是串行执行。

同一个虚拟机可以相互访问

假如我们需要并发的执行js代码,我们也可以在创建JSContext的时候也指定其所在的虚拟机,不同的虚拟机处于不同的线程中,但是如果在不同的 JSVirtualMachine,上下文并不能直接互相传值,在使用的过程中需要注意一下。

JSVirtualMachine *vm1 = [JSVirtualMachine new];
JSContext *ctxA1 = [[JSContext alloc] initWithVirtualMachine:vm1]; JSContext *ctxA2 = [[JSContext alloc] initWithVirtualMachine:vm1]; JSVirtualMachine *vm2 = [JSVirtualMachine new]; JSContext *ctxB = [[JSContext alloc] initWithVirtualMachine:vm2];

不同一个虚拟机不可以相互访问

参考

https://developer.apple.com/videos/play/wwdc2013/615/
https://developer.apple.com/library/prerelease/ios/documentation/Carbon/Reference/WebKit_JavaScriptCore_Ref/

文/树下的老男孩(简书作者)
原文链接:http://www.jianshu.com/p/1328e15416f3/comments/1724404
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

说说JavaScriptCore相关推荐

  1. 转载 iOS js oc相互调用(JavaScriptCore) --iOS调用js

    iOS js oc相互调用(JavaScriptCore) 从iOS7开始 苹果公布了JavaScriptCore.framework 它使得JS与OC的交互更加方便了. 下面我们就简单了解一下这个框 ...

  2. iOS下JS与OC互相调用(四)--JavaScriptCore

    前面讲完拦截URL的方式实现JS与OC互相调用,终于到JavaScriptCore了.它是从iOS7开始加入的,用 Objective-C 把 WebKit 的 JavaScript 引擎封装了一下, ...

  3. iOS中JS 与OC的交互(JavaScriptCore.framework)

    iOS中实现js与oc的交互,目前网上也有不少流行的开源解决方案: 如:react native 当然一些轻量级的任务使用系统提供的UIWebView 以及JavaScriptCore.framewo ...

  4. (0085)iOS开发之OC与JS交互高级用法(JavaScriptCore)

    前述:JavaScriptCore你不知道的OC与JS之间交互.OC与JS之间用model实现交互.通讯.传值!好玩! 几乎三年来一直断断续续接触OC与JS交互,每次觉得UIWebView OC与JS ...

  5. (0006) iOS 开发之JavaScriptCore 实现UIWebView和HTML的交互

    阅读说明:本文不讲解JavaScriptCore 基本使用.网上博客比较多,看几篇基本都会使用了.这里只针对使用过程中遇到的一些问题.以便更好的使用JavaScriptCore. 由于开发的项目是电商 ...

  6. iOS js oc相互调用(JavaScriptCore)(二)

    http://blog.csdn.net/lwjok2007/article/details/47058795 上节地址 http://blog.csdn.net/lwjok2007/article/ ...

  7. 浅谈 JavaScriptCore

    来源:XcodeMen(王瑞华) 链接:http://t.cn/RVqQI5p 本文由我们团队的王瑞华童鞋撰写. OS X Mavericks 和 iOS 7 引入了 JavaScriptCore 库 ...

  8. 浅谈WebKit之JavaScriptCore/V8

    WebKit作为一个浏览器引擎,其中Javascript实现包括JavaScriptCore和V8,为了能更全面的了解WebKit,我们需要深入的了解Javascript实现的基本原理.其在WebKi ...

  9. JavaScriptCore API 和V8 API

    JavaScriptCore主要正调接口 JavaScriptCore中的主要正调API API描述 JSClassCreate 创建一个JavaScript对象的类,这个类可以用以创建JavaScr ...

最新文章

  1. 查询存储过程所需参数
  2. Android--查找程序根目录下所有文件/Java IO操作
  3. 连续特征离散化方法介绍
  4. CentOS7.6安装WirёGuαrd(一)
  5. 6678EMIF总结
  6. 计算机房面积设置气消条件,机房消防设计方案
  7. 古剑奇谭3steam服务器稳定吗,国产游戏《古剑奇谭3》占据steam热销榜第一?这么好玩吗?...
  8. hbase snappy 安装_【hbase-部署】配置snappy压缩
  9. 安卓紧急警报_我们的紧急警报系统依赖于重叠的私有服务混乱局面
  10. L1-6 斯德哥尔摩火车上的题
  11. 【PMP】核对单和核查表的区别
  12. 图片批量重命名方法(超详细 无需辅助软件 本地运行)
  13. ActiveX控件属性的下拉列表
  14. 【D3.js 学习总结】12、D3布局-集群图
  15. 前端如何实现选项卡效果?
  16. 计网 | Cisco Packet Tracer下模拟交换机及VLAN配置实验记录
  17. 化工原理 --- 流体传送机械
  18. 大数据系统基础 | 绪论
  19. MVC的Model层验证(非空,手机号验证)
  20. ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY

热门文章

  1. 清华出品:一文看尽AI芯片两类瓶颈三大趋势,存储技术开拓新疆界 | 附全文...
  2. spawn-fcgi启动的一些报错问题
  3. 《R语言数据挖掘:实用项目解析》——第2章,第2.9节无参数方法
  4. mongodb query
  5. 织梦根目录下面404页面,主页能正常运行404页面,切换至栏目页404页面内的图片不能正常显示,解决...
  6. 自然语言处理常用工具
  7. excel表格最大行数
  8. Spring Aop实例
  9. 数据绑定控件之DataList
  10. GridView中实现单选RadioButton