版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.11.05 |
前言
JavaScriptCore
是用来评估应用程序中的JavaScript
程序,并支持应用程序的JavaScript脚本编写。接下来这几篇我们就详细的解析一下JavaScriptCore框架的使用情况。感兴趣的可以看上面写的那篇。
1. JavaScriptCore 框架详细解析(一) —— 基本概要
2. JavaScriptCore 框架详细解析(二) —— JS与OC通信
内存管理
正常情况下,OC和JS对象之间内存管理都无需我们去关心。但是有几个方面需要我们注意。
1. 不要在block里面直接使用context,或者使用外部的JSValue对象
下面我们看一个错误例子。
self.context[@"block"] = ^(){
JSValue *value = [JSValue valueWithObject:@"aaa" inContext:self.context];
};
上面的就是个错误代码,编译器就会提示你的,block里面包含self,构成循环引用,引起内存问题。下面看一个隐蔽的。
JSValue *value = [JSValue valueWithObject:@"ssss" inContext:self.context];
self.context[@"log"] = ^(){
NSLog(@"%@",value);
};
这里需要说明的是引入了外面的value,value对context和其管理的JS对象均为强引用,block里面是context对JS进行强引用,构成了循环引用而泄露,context是不能销毁的。
2. OC对象不要用属性直接保存JSValue对象
//用来保存JS的对象
@property (nonatomic, strong) JSvalue *jsValue;
...
@property (nonatomic, strong) JSProtocolObj *obj;
...
//加载JS代码到context中
[self.context evaluateScript:
@"function callback (){};
function setObj(obj) {
this.obj = obj;
obj.jsValue=callback;
}"];
...
//调用JS方法
[self.context[@"setObj"] callWithArguments:@[self.obj]];
上面的例子调用JS方法,进行赋值,JS对象保留了传进来的obj,最后,JS将自己的回调callback赋值给了obj,方便obj下次回调给JS。由于JS那边保存了obj,而且obj这边也保留了JS的回调。这样就形成了循环引用。
下面我们就看一下如何解决这样的循环引用带来的内存问题。
解决方法就是使用JSManagedValue
,JSManagedValue
本身就是我们需要的弱引用。用官方的话来说叫garbage collection weak reference
。但是它帮助我们持有JSValue对象必须同时满足一下两个条件。
The JSManagedValue's JavaScript value is reachable from JavaScript
The owner of the managed reference is reachable in Objective-C. Manually adding or removing the managed reference in the JSVirtualMachine determines reachability.
JSManagedValue
帮助我们保存JSValue,那里面保存的JS对象必须在JS中存在,同时 JSManagedValue 的owner在OC中也存在。我们可以通过它提供的两个方法
+ (JSManagedValue )managedValueWithValue:(JSValue )value;
-
(JSManagedValue )managedValueWithValue:(JSValue )value andOwner:
(id)owner创建JSManagedValue对象。通过JSVirtualMachine
的方法- (void)addManagedReference:(id)object withOwner:(id)owner
来建立这个弱引用关系。通过- (void)removeManagedReference:(id)object withOwner:(id)owner
来手动移除他们之间的联系。
所以可以修改代码,如下所示。
//重写setter方法
- (void)setJsValue:(JSValue *)jsValue
{
_managedValue = [JSManagedValue managedValueWithValue:jsValue];
[[[JSContext currentContext] virtualMachine] addManagedReference:_managedValue
withOwner:self];
}
3. 不要在不同的 JSVirtualMachine 之间进行传递JS对象
一个 JSVirtualMachine
可以运行多个context
,由于都是在同一个堆内存和同一个垃圾回收下,所以相互之间传值是没问题的。但是如果在不同的 JSVirtualMachine
传值,垃圾回收就不知道他们之间的关系了,可能会引起异常。
线程
JavaScriptCore
线程是安全的,每个context运行的时候通过lock
关联的JSVirtualMachine
。如果要进行并发操作,可以创建多个JSVirtualMachine实例进行操作。
后记
未完,待续~~~