JSManagedValue を使用しようとしているときに問題が発生しました。WWDC 2013 のセッション 615 に基づく私の理解から、Objective-C から Javascript への参照、およびその逆の参照が必要な場合は、JSValue を Objective-C に格納するだけでなく、JSManagedValue を使用して参照を回避する必要があります。サイクル。
これは、私がやろうとしていることの簡素化されたバージョンです。Javascript オブジェクトへの参照が必要な ViewController があり、その Javascript オブジェクトは ViewController でメソッドを呼び出すことができる必要があります。ViewController には、カウントを表示する UILabel と、カウントをインクリメントする 'Add' と、現在のビュー コントローラを作成して新しい ViewController に置き換える 'Reset' の 2 つの UIButton があります (基本的には、古い ViewController を確認できるようにするためです)。これをテストしている間、適切にクリーンアップされます)。
ではviewDidLoad
、ViewController が呼び出さupdateLabel
れ、Javascript オブジェクトからカウントを正しく取得できます。ただし、その実行ループが終了した後、Instruments は JSValue が解放されていることを示しています。JSManagedValue と同様に、ViewController はまだ存在するため、JSValue がガベージ コレクションされるのを防ぐべきだと考えましたが、_managedValue.value
nil を返します。
JSManagedValue を使用する代わりに JSValue を保存すると、視覚的にはすべて機能しますが、予想どおり、ViewController と JSValue の間に参照サイクルがあり、Instruments は ViewControllers が決して解放されないことを確認します。
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 の存続期間全体にわたって保持されるように、このセットアップを処理する正しい方法は何ですか?