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.js
var 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引入JavaScriptCore引擎框架(一)

    JavaScriptCore引擎     我们都知道WebKit是个渲染引擎,简单来说负责页面的布局,绘制以及层的合成,但是WebKit工程中不仅仅有关于渲染相关的逻辑,也集成了默认的javascri ...

  2. 判断js引擎是javascriptCore或者v8

    来由   纯粹的无聊,一直在搜索JavaScriptCore和SpiderMonkey的一些信息,却无意中学习了如何在ios的UIWebView中判断其js解析引擎的方法: if (window.de ...

  3. WKWebView与JS交互,UIWebView+JavascriptCore和JS交互

    最近一直在做有关Swift和JavaScript交互的程序,所以有关UIWebView和WKWebView在使用上的差别在此总结下: UIWebView: (1)创建 var webView: UIW ...

  4. iOS JavaScriptCore与H5交互时出现异常提示

    在利用JavaScriptCore与H5交互时出现异常提示: This application is modifying the autolayout engine from a background ...

  5. JavaScriptCore 使用

    JavaScriptCore JavaScriptCore是webkit的一个重要组成部分,主要是对JS进行解析和提供执行环境.代码是开源的,可以下下来看看(源码).iOS7后苹果在iPhone平台推 ...

  6. JavaScriptCore框架介绍

    http://www.cocoachina.com/ios/20140409/8127.html 这个框架其实只是基于webkit中以C/C++实现的JavaScriptCore的一个包装,在旧版本i ...

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

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

  8. iOS7新JavaScriptCore框架入门介绍

    前阵子,Apple正式发布了新的iOS 7系统,最大最直观的改变在于界面变得小清新范了,我也提到<iOS,你真的越来越像Android了>.不过对于移动开发者来说,除了要适应Xcode 5 ...

  9. iOS7 中的JavaScriptCore简单介绍

    以前写过一篇介绍如何使用第三方库在ios上进行js和oc交互调用的文章,链接如下 iOS 使用UIWebView把oc代码和javascript相关联.当时建立项目时,仍然是ios6时代,所以没有原生 ...

随机推荐

  1. .NET架构设计、框架设计系列文章总结

    从事.NET开发到现在已经有七个年头了.慢慢的可能会很少写.NET文章了.不知不觉竟然走了这么多年,热爱.NET热爱c#.突然想对这一路的经历进行一个总结. 是时候开始下一阶段的旅途,希望这些文章可以 ...

  2. 聊下 git 使用前的一些注意事项

    连接方式https.ssh 在使用git的时候,不管你的服务器是开源平台github还是私服gitlab,你都需要clone仓库到本地,这个clone的时候就需要你选择连接方式.这个连接方式决定了你与 ...

  3. SQL闲杂知识点汇总【2015年12月】

    2015.12.14 知识点1:DEFAULT VALUES实现插入行 --临时创建临时表 CREATE TABLE [dbo].[tblTmp] ( iTmpID ,) NOT NULL PRIMA ...

  4. x01.Weiqi.9: 点目功能

    添加点目功能,虽不中,不远也.还是先看看截图吧. 确保其可行,再看一张: 其点目结果,还是比较令人满意的.这主要得益于多遍扫描,如编译器的词法分析阶段,下面的代码可以证明: private void ...

  5. jsp2.0+中的标签文件,JSP Fragment技术

    刚进新公司不久,今天在看到项目中用到了.tag文件.刚开始我还以为这个是第三方类似freemarker的模板技术.问了下项目组的其他人员,原来这是jsp2.0以来就有的JSP Fragment技术.以 ...

  6. LLVM 笔记(五)—— LLVM IR

    ilocker:关注 Android 安全(新手) QQ: 2597294287 LLVM 的 IR (Intermediate Representation) 是其设计中的最重要的部分.优化器在进行 ...

  7. 如何安装虚拟机VMware

    虚拟机可以帮我们在一台电脑上面来模拟出多台电脑,而且可以装不同的系统.下面就教大家怎么装VMware虚拟机 1.下载Vmware安装包,建议下载VMware10 这个有中文版的,其他版本的都是英文的哦 ...

  8. Android Studio failed to open by giving error “Files Locked” 解决方案

    windows 7 下的解决方案 导航至 android-studio 安装目录. (默认为C:\Program Files (x86)\Android\android-studio). 往上一层文件 ...

  9. 利用firebug调试功能辅助了解闭包和this

    算一算,有段时间没写博客. 上午的时候翻看以前收藏的一个系列博文<深入理解javascript原型和闭包>, 讲闭包那节:http://www.cnblogs.com/wangfupeng ...

  10. UVA 11859 Division Game[Nim游戏]

    题意:给定一个N*M的矩阵,每次可以选择同一行中的若干个数,把它们变成它们的质因子.问说先手的可否获胜. 同一行相当于1堆,数量就是所有数的质因子个数之和 #include <iostream& ...