【发布时间】:2013-10-05 20:14:32
【问题描述】:
我在尝试使用 JSManagedValue 时遇到了问题。根据我基于Session 615 at WWDC 2013 的理解,当您想要从Objective-C 引用到Javascript 时,反之亦然,您需要使用JSManagedValue 而不是仅仅将JSValue 存储在Objective-C 中以避免引用循环。
这是我正在尝试做的精简版。我有一个需要引用 Javascript 对象的 ViewController,并且该 Javascript 对象需要能够调用 ViewController 上的方法。 ViewController 有一个显示计数的 UILabel,并有两个 UIButton,“Add”增加计数,“Reset”创建并用新的 ViewController 替换当前的视图控制器(基本上只是为了验证旧的 ViewController在我测试这个时被正确清理)。
在viewDidLoad 中,ViewController 调用updateLabel 并能够正确地从 Javascript 对象中获取计数。但是,在该运行循环结束后,Instruments 显示 JSValue 正在被释放。 ViewController 仍然存在,它的 JSManagedValue 也是如此,所以我认为这应该可以防止 JSValue 被垃圾收集,但 _managedValue.value 现在返回 nil。
如果我只存储 JSValue 而不是使用 JSManagedValue,这一切都可以直观地工作,但正如预期的那样,ViewController 和 JSValue 之间存在引用循环,并且 Instruments 确认 ViewController 永远不会释放。
Javascript 代码:
(function() {
var _count = 1;
var _view;
return {
add: function() {
_count++;
_view.updateLabel();
},
count: function() {
return _count;
},
setView: function(view) {
_view = view;
}
};
})()
CAViewController.h
@protocol CAViewExports <JSExport>
- (void)updateLabel;
@end
@interface CAViewController : UIViewController<CAViewExports>
@property (nonatomic, weak) IBOutlet UILabel *countLabel;
@end
CAViewController.m
@interface CAViewController () {
JSManagedValue *_managedValue;
}
@end
@implementation CAViewController
- (id)init {
if (self = [super init]) {
JSContext *context = [[JSContext alloc] init];
JSValue *value = [context evaluateScript:@"...JS Code Shown Above..."];
[value[@"setView"] callWithArguments:@[self]];
_managedValue = [JSManagedValue managedValueWithValue:value];
[context.virtualMachine addManagedReference:_managedValue withOwner:self];
}
return self;
}
- (void)viewDidLoad {
[self updateLabel];
}
- (void)updateLabel {
JSValue *countFunc = _managedValue.value[@"count"];
JSValue *count = [countFunc callWithArguments:@[]];
self.countLabel.text = [count toString];
}
- (IBAction)add:(id)sender {
JSValue *addFunc = _managedValue.value[@"add"];
[addFunc callWithArguments:@[]];
}
- (IBAction)reset:(id)sender {
UIApplication *app = [UIApplication sharedApplication];
CAAppDelegate *appDelegate = app.delegate;
CAViewController *vc = [[CAViewController alloc] init];
appDelegate.window.rootViewController = vc;
}
处理此设置的正确方法是什么,以便在 ViewController 的整个生命周期中保留 JSValue,但不创建引用循环以便可以清理 ViewController?
【问题讨论】:
标签: javascript objective-c javascriptcore