JavaScriptCore---ViWu

前生后世

JavaScriptCore 是苹果 Safari 浏览器的JavaScript 引擎,在 OS X 平台上很早就存在的,而在 iOS 平台,直到IOS7才对外开放,并提供了 Objective-C 的接口,极大的方便了我们对js的操作。我们可以脱离webview直接运行我们的js。iOS7以前我们对JS的操作只有webview里面一个函数 stringByEvaluatingJavaScriptFromString,JS对OC的回调都是基于URL的拦截进行的操作。大家用得比较多的是WebViewJavascriptBridgeEasyJSWebView这两个开源库,很多混合都采用的这种方式。

  JavaScriptCore是webkit的一个重要组成部分,主要是对JS进行解析和提供执行环境。代码是开源的,可以下下来看看源码)。

全家桶

首先引入框架 #import <JavaScriptCore/JavaScriptCore.h>

主要包括以下五个类

#import "JSContext.h" <br/>
#import "JSValue.h" <br/>
#import "JSManagedValue.h"<br/>
#import "JSVirtualMachine.h"<br/>
#import "JSExport.h"<br/>
JSContext.h

一个 Context 就是一个 JavaScript 代码执行的环境,也叫作用域。
同时也通过JSVirtualMachine管理着所有对象的生命周期,每个JSValue都和JSContext相关联并且强引用context。

JSValue.h

JS是弱类型的,ObjectiveC是强类型的,JSValue被引入处理这种类型差异,在 Objective-C 对象和 JavaScript 对象之间起转换作用;另外,每个JSValue都是强引用一个context。

以下是JS OC Swift 类型对应图例

jsType.png
jsType3.png
JSManagedValue.h

JS和OC对象的内存管理辅助对象。由于JS内存管理是垃圾回收,并且JS中的对象都是强引用,而OC是引用计数。如果双方相互引用,势必会造成循环引用,而导致内存泄露。我们可以用JSManagedValue保存JSValue来避免。

JSVirtualMachine.h

JS运行的虚拟机,有独立的堆空间和垃圾回收机制。

JSExport.h

在 JavaScript 代码中使用我们的自定义对象的方法是添加 JSExport 协议。无论我们在 JSExport 里声明的属性,实例方法还是类方法,继承的协议都会自动的提供给任何 JavaScript 代码。

通信

• Objective-C or swift → JavaScript

• JavaScript → Objective-C or swift

swift → JavaScript

大致步骤如下:

  • 创建JSContext对象(可以设置异常处理)
  • 加载JS代码
  • 访问JSVAlue
jsToc.png
JavaScript → swift

JSContext 访问我们的本地客户端代码的方式主要有两种:block 和 JSExport 协议。

block

当一个 Objective-C block 被赋给 JSContext 里的一个标识符,JavaScriptCore 会自动的把 block 封装在 JavaScript 函数里。这使得在 JavaScript 中可以简单的使用 Foundation 和 Cocoa 类,所有的桥接都为你做好了。

ocTjs-block.png

Note

1.内存管理:由于 block 可以保有变量引用,而且 JSContext 也强引用它所有的变量,为了避免强引用循环需要特别小心。避免保有你的 JSContext 或一个 block 里的任何 JSValue。相反,使用 [JSContext currentContext] 得到当前上下文,并把你需要的任何值用参数传递。简单的说 jsvalue = [valueWithObject:inContext:[JSContext currentContext]]

2.swift:要在 JSContext 中使用 Swift 闭包,它需要(a)与 @ objc_block 属性一起声明,以及(b)使用 Swift 那个令人恐惧的 unsafeBitCast() 函数转换为 AnyObject ***。

JSExport

在 JavaScript 代码中使用我们的自定义对象的方法是添加 JSExport 协议。无论我们在 JSExport 里声明的属性,实例方法还是类方法,继承的协议都会自动的提供给任何 JavaScript 代码。Mustache JS library

note

唯一要注意的是OC的函数命名和JS函数命名规则问题。
#define JSExportAs(PropertyName, Selector)
@optional Selector JS_EXPORT_AS##PropertyName:(id)argument;
@required Selector
#endif

比如:协议中定义的是add: b:,但是JS里面方法名字是addB(a,b)。可以通过JSExportAs这个宏转换成JS的函数名字。

JSExportAs(add, - (NSInteger)add:(NSInteger)a b:(NSInteger)b);

内存管理

1• Objective-C uses ARC(OC 使用ARC机制)

2• JavaScriptCore uses garbage collection (JS 使用垃圾回收机制)

■ All references are strong (JS中全部都是“强引用”)

3• API memory management is mostly automatic

4• Two situations that require extra attention: (几乎SDK已经做好了很多事情,所以开发者只需要重点掌握以下亮点)

■ Storing JavaScript values in Objective-C objects

■ Adding JavaScript fields to Objective-C objects

根据官方文档关于JS-OC内存管理总结:由于JS中全部都是强引用,如果JS 与 OC互相引用时,就要防止OC也强引用JS,这样会形成引用循环,所以OC要想办法弱引用,但弱引用会被系统释放,所以把可能被释放的对象放到一个容器中来防止对象被被错误释放。


1.不要在block里面直接使用context,或者使用外部的JSValue对象。

如果需要引用,jsvalue = [valueWithObject:inContext:[JSContext currentContext]]


2.OC对象不要同时引用同一个对象,因为这样太容易循环引用了

解决方案

JSManagedValue:

  The primary use case for JSManagedValue is for safely referencing JSValues from the Objective-C heap. It is incorrect to store a JSValue into an Objective-C heap object, as this can very easily create a reference cycle, keeping the entire JSContext alive.

(将 JSValue 转为 JSManagedValue 类型后,可以添加到 JSVirtualMachine 对象中,这样能够保证你在使用过程中 JSValue 对象不会被释放掉,当你不再需要该 JSValue 对象后,从 JSVirtualMachine 中移除该 JSManagedValue 对象,JSValue 对象就会被释放并置空。)

JSVirtualMachine: All instances of JSContext are associated with a single JSVirtualMachine. The virtual machine provides an "object space" or set of execution resources.

(JSVirtualMachine就是一个用于保存弱引用对象的数组,加入该数组的弱引用对象因为会被该数组 retain,所以保证了使用时不会被释放,当数组里的对象不再需要时,就从数组中移除,没有了引用的对象就会被系统释放。)

JSManagedValue 帮助我们保存JSValue,那里面保存的JS对象必须在JS中存在,同时 JSManagedValue 的owner在OC中也存在。我们可以通过它提供的两个方法。

+ (JSManagedValue )managedValueWithValue:(JSValue )value;<br/>

-(JSManagedValue )managedValueWithValue:(JSValue )value andOwner:(id)owner创建JSManagedValue对象。<br/>

通过JSVirtualMachine的方法- (void)addManagedReference:(id)object withOwner:(id)owner来建立这个弱引用关系。
通过- (void)removeManagedReference:(id)object withOwner:(id)owner``` 来手动移除他们之间的联系。

使用方式

_managedValue = [JSManagedValue managedValueWithValue:jsValue];

[[[JSContext currentContext] virtualMachine] addManagedReference:_managedValue 
withOwner:self];

线程安全

• API is thread safe

• Locking granularity is JSVirtualMachine

■ Use separate JSVirtualMachines for concurrency/parallelism

JavaScriptCore 线程是安全的,每个context运行的时候通过lock关联的JSVirtualMachine。

如果要进行并发操作,可以创建多个JSVirtualMachine实例进行操作。

JavaScriptCore C API

JSValue ↔ JSValueRef :

   JSValueRef valueRef = XXX;
   JSValue *value = [JSValue valueWithJSValueRef:valueRef inContext:context];

   JSValue *value =  XXX;
   JSValueRef valueRef = [value JSValueRef];

JSContext ↔ JSGlobalContextRef :

    JSGlobalContextRef ctx =  XXX;
    JSContext *context = [JSContext contextWithJSGlobalContextRef:ctx];

    JSContext *context =  XXX;
    JSGlobalContextRef ctx = [context JSGlobalContextRef];

与UIWebView的操作

             self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

参考我文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容