JSManagedValueの使用中に問題が発生しています。 Session 615 at WWDC 2013に基づく私の理解では、Objective-CからJavascriptへの参照、またはその逆の参照が必要な場合は、参照サイクルを避けるためにJSValueをObjective-Cに格納するのではなく、JSManagedValueを使用する必要があります。JSManagedValueを使用して、JSValueを解放せずに参照サイクルを回避するにはどうすればよいですか?
ここでは、私がしようとしているものを取り除いたものです。私は、Javascriptオブジェクトへの参照を必要とするViewControllerを持っており、そのJavascriptオブジェクトはViewControllerのメソッドを呼び出すことができる必要があります。 ViewControllerには、カウントを表示するUILabelがあり、カウントをインクリメントする 'Add'と、現在のView Controllerを作成して新しいViewControllerに置き換える 'Reset'という2つのUIButtonがあります(基本的には古いViewController私はこれをテストしている間に適切にクリーンアップされます)。
viewDidLoad
では、ViewControllerはupdateLabel
を呼び出し、Javascriptオブジェクトから正しくカウントを取得できます。しかし、その実行ループが終了した後、InstrumentsはJSValueがリリースされていることを示しています。 ViewControllerはJSManagedValueと同じようにまだ存在しているので、JSValueがガベージコレクトされるのを防ぐべきだと思ったが、_managedValue.value
はnilを返すようになった。
JSManagedValueを使用する代わりにJSValueを格納するだけであれば、すべて視覚的に動作しますが、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;
}
JSValueがViewControllerのライフタイム全体にわたって保持されるようにこの設定を処理する正しい方法ですが、ViewControllerをクリーンアップできるように参照サイクルは作成されません。
これは正しいと思います。私はセッション615のビデオからソースコードを読んで、これを確認することを余儀なくされています。サンプルプロジェクトがまだ利用可能であればいいでしょう。 – Poulsbo
サンプルコードは現在ここにあります:https://developer.apple.com/downloads/index.action?name=WWDC%202013 – Poulsbo