iOS Dev难免会遇上需要和JavaScript交互的时候,我是这么做的。
JavaScriptCore
JSC是webkit的一部分,主要是对JS进行解析和提供执行环境,并且,他是开源的。
JavaScriptCore源码
在iOS7推出后,JSC极大的方便了开发者对js的操作。在此之前通用的方法都是是用webview
里面的一个函数stringByEvaluatingJavaScriptFromString
,JS 对Native的回调都是通过拦截URL的方式进行的。
JSC中和我们相关的类就大概只有一下5个。
|
|
JSContext
JS执行的环境,同时也通过JSVirtualMachine管理着所有对象的生命周期,每个JSValue都和JSContext相关联并且强引用context。
JSValue
JS对象在JSVirtualMachine中的一个强引用,其实就是Hybird对象。我们对JS的操作都是通过它。并且每个JSValue都是强引用一个context。同时,OC和JS对象之间的转换也是通过它,相应的类型转换如下:
Obj-C type | JS type |
---|---|
nil | undefined |
NSNull | null |
NSString | string |
NSNumber | number,boolean |
NSDictionary | Object object |
NSArray | Object object |
NSDate | Date object |
NSBlock | Function object |
id | Wrapper object |
Class | Constructor object |
JSManagedValue
JS和OC对象的内存管理辅助对象。由于JS内存管理是垃圾回收,并且JS中的对象都是强引用,而OC是引用计数。如果双方相互引用,势必会造成循环引用,而导致内存泄露。我们可以用JSManagedValue保存JSValue来避免。
JSVirtualMachine
JS运行的虚拟机,有独立的堆空间和垃圾回收机制。
JSExport
一个协议,如果JS对象想直接调用OC对象里面的方法和属性,那么这个OC对象只要实现这个JSExport协议就可以了。
交互过程
分别是OC -> JS 、 JS -> OC
首先在工程中引入JSC。
JS -> OC
这种情况的使用的应该是最多的, 可能你在一个H5页面中要跳转到native页面等等。
我写了一个Demo,并写了一个相关的html代码。
步骤:
1、定义一个协议PsJsObjcDelegate
|
|
2、定义一个遵守这个协议的Object JsObjcBridge
|
|
因为我选择了通过block来进行这个class 和 vc之间的调用,所以我定义了一个blockproperty
来进行这个对象和vc之间的调用。
3、协议方法 (注意这里的方法名要和js中的一致)
|
|
4、在 JsObjcBridge
中实现这个方法
|
|
5、把那个`.html`文件导入工程
6、在Controller中编码
|
|
OC -> JS
一种是向js 中注入新的js代码、一种是调用js中已有方法。
由于我实在想不到好的应用场景,所以就只能在一个导航栏中左右分别放两个item
|
|
|
|
当然你要调用或者注入的js function 是有返回值的那么上面的一句话就应该改成这样了
内存管理
写博文的时候查阅相关资料发现这里还是可能会出现一些循环引用的问题。然后简单整理了一下。
- OC 的
ARC
和 JS的GC
- 正常情况下
GC
都会打破循环引用
特殊情况:
- 不要在block里面直接使用context,或者使用外部的
JSValue
对象。 - OC对象不要用属性直接保存
JSValue
对象,因为这样太容易循环引用了。 - 不要在不同的
JSVirtualMachine
之间进行传递JS对象。
结束的话
不多说了,只是简单的实现了一下,肯定还是有很多的东西没有考虑到,以后遇到了再完善吧。demo地址。在写这个博客的过程中思考了许多,其实在具体场景中还是有很多东西没有想到。而且在代码中调用的方法什么的卸写在一个plist
里面,把各种规则放进去,这样更利于维护,和与sever
的交互。这些可能都需要去思考的问题。原谅我比较low,并没有在项目中有过这样的应用。吾将上下而求索…